Reflection 클래스 정보


Java에서 제공하는 Relfection API를 통해 동적으로 클래스에 관련된 정보를 가져올 수 있다.

* Class 클래스 주요 메소드
String getName() : 패키지 포함 해당 클래스명 리턴
String getSimpleName() : 해당 클래스명 리턴
Field[] getFields() : public으로 선언된 변수 목록 리턴
Field[] getDeclaredFields() : 해당 클래스에 선언된 모든 변수 리턴
Method[] getMethods() : public으로 선언된 메소드 목록 리턴(해당 클래스에서 사용 가능한 상속 받은 메소드 포함)
Method[] getDeclaredMethods() : 해당 클래스에 선언된 모든 메소드 리턴
Constructor[] getDeclaredConstructors() : 해당 클래스에 선언된 모든 생성자 리턴
int getModifiers() : 해당 클래스의 접근자 정보 리턴
String toString() : 해당 클래스 객체를 문자열로 리턴

* Method 클래스 주요 메소드
String getName() : 해당 메소드명 리턴
int getModifiers() : 해당 메소드의 접근자 정보 리턴
String toString() : 해당 메소드 정보 리턴
Object invoke(Object obj, Object... args) : 해당 메소드 수행
Class<?> getDeclaringClass() : 해당 메소드가 선언된 클래스 정보 리턴
Class<?> getReturnType() : 해당 메소드 리턴 타입 리턴
Class<?>[] getExceptionTypes() : 해당 메소드 예외 타입들 리턴
Class<?>[] getParameterTypes() : 해당 메소드 매개변수 타입들 리턴

* Field 클래스 주요 메소드
String getName() : 해당 변수명 리턴
int getModifiers() : 해당 변수의 접근자 정보 리턴
String toString() : 해당 변수 정보 리턴

Modifier.toString(int modifier) : int 타입으로 리턴받은 modifier 값을 문자열로 리턴

* 참고사항
- 로그 선언시 클래스 이름을 알아내기 위해 this.getClass().getName() 사용한다고 성능이 크게 저하되지는 않는다. 
  하지만 클래스 객체를 얻는 방법 보다는 클래스명을 직접 명시하는 것을 권장한다.
- 클래스의 이름으로 해당 객체의 타입인지 비교하는 방법 보다 instanceof 키워드를 사용하는 것이 성능이 우수하다.
클래스의 메타 데이터 정보는 JVM의 Perm 영역에 저장된다. 
   Class 클래스를 사용하여 많은 양의 클래스를 동적으로 생성하면 Perm 영역을 더 이상 사용할 수 없게 되어 OutOfMemoryError가 발생한다.

참고서적 - 자바 성능 튜닝 이야기


'Development > Java' 카테고리의 다른 글

Garbage Collection 과정  (0) 2018.04.28
Garbage Collection 용어 정리  (0) 2018.04.26
AES256 암호화 오류 해결  (4) 2017.10.06
반복문 성능 비교  (0) 2017.07.27
List 중복 제거  (0) 2017.07.13

요청 포워딩 처리

요청에 대한 응답을 누가할지 선택할 수 있다.
웹 애플리케이션에 있는 다른 컴포넌트에게 처리를 위임하거나 요청을 완전히 다른 URL로 방향을 바꿀 수 있다.

1. RequestDispatcher 클래스를 이용한 forward 방법

웹 브라우저를 통해 사용자가 서블릿에 최초 요청하면 HttpServletRequest 객체가 자동으로 생성된다.
이 request 객체를 사용해 응답을 처리하는 웹 컴포넌트(서블릿, JSP, HTML)로 재요청하는 방식이다.
최초/재요청 동일한 HttpServletRequest 객체를 사용하기 때문에 URL 변동이 없다.
따라서 웹 브라우저 입장에서는 누가 처리한 것인지 알 수 없다.
또한, 동일한 객체를 사용하기 때문에 최초 요청시 request scope에 attribute를 설정하면 재요청시 설정된 attribute 값을 가져올 수 있다.

1
2
RequestDispatcher dispatcher = request.getRequestDispatcher(target);
dispatcher.forward(request, response);
cs

2. HttpServletResponse 클래스를 이용한 redirect 방법

forward 방식과 동일하게 다른 웹 컴포넌트에게 재요청하는 방식이다.
차이점은 최초 요청에 대한 응답시 HttpServletResponse 객체의 상태코드 헤더에 301 값과 Location 헤더에 새로운 URL 값을 포함시킨다.
웹 브라우저는 응답받은 URL로 재요청하기 때문에 동일한 HttpServletRequest가 아닌 새로운 request 객체가 생성된다.
따라서 URL이 변경되고 attribute에 설정된 값을 가져올 수 없다.

1
response.sendRedirect(target);
cs


JDBC 오라클 데이터베이스 연동하기


먼저 오라클 데이터베이스 설치하여 emp 테이블을 생성한 전제로 진행한다. (다운로드 - www.oracle.com)
오라클 드라이버를 클래스 패스에 설정해야 자바 애플리케이션과 오라클 데이터베이스를 연동할 수 있다.
[Windows]-[Preferences]-[Java]-[Build Path]-[ClassPath Variables]에 있는 JRE_LIB 경로를 파악하여
lib\ext 디렉토리에 오라클 설치경로(C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib)에 있는'ojdbc6_g.jar'
파일을 복사하면 자동으로 드라이버가 클래스 패스에 추가된다.

* Select 쿼리 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@WebServlet("/select")
public class SelectServlet extends HttpServlet {
 
    private static final long serialVersionUID = -2214077158028938610L;
 
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        String driver = "oracle.jdbc.OracleDriver"// 오라클 드라이버 클래스 파일명
        String url = "jdbc:oracle:thin:@localhost:1521:XE"// 오라클 위치,포트번호,DB정보
        String id = "root"// 오라클 접속 계정
        String password = "1234"// 오라클 접속 비밀번호
 
        Connection con = null;
        Statement stmt = null;
        ResultSet rs = null;
        String result = null;
        
        try {
            Class.forName(driver); // 드라이버 로딩
            con = DriverManager.getConnection(url, id, password); // DB 커넥션 맺기
 
            String sql = "select eid, ename, salary from emp";
            stmt = con.createStatement();
            rs = stmt.executeQuery(sql);
 
            while (rs.next()) {
                String eid = rs.getString("eid");
                String ename = rs.getString("ename");
                int salary = rs.getInt("salary");
                result  = eid + " " + ename + " " + salary;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try { // 자원 반납
                if (rs != null)
                    rs.close();
                if (stmt != null)
                    stmt.close();
                if (con != null)
                    con.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
 
        request.setAttribute(result, result);
        response.setCharacterEncoding("UTF-8");
        request.getRequestDispatcher("/select.jsp").forward(request, response);
    }
 
}
cs
Select 쿼리 요청에는 executeQuery 메소드를 사용하여 테이블 형태인 ResultSet 객체를 얻는다.
ResultSet 객체는 포인터를 이용해서 원하는 데이터를 얻을 수 있기 때문에 먼저 포인터를 이용해서 레코드를 선택하고 포인터가 가리키는 레코드의 컬럼을 지정해서 데이터를 얻는다. 레코드를 선택하는 메소드는 next()를 사용하고 컬럼은 데이터형에 맞는 get*(컬럼명)메소드를 사용한다.

파일 및 데이터베이스는 외부 자원이기 때문에 사용한 후에는 반드시 자원을 해제시켜야 된다. 해제시킬 때에는 사용한 역순으로 해제시킨다.
예외 발생 여부에 관계없이 항상 자원을 반납해야하므로 finally 문에 코드를 구현하도록 한다.

* Update 쿼리 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@WebServlet("/update")
public class UpdateServlet extends HttpServlet {
 
    private static final long serialVersionUID = -2214077158028938610L;
 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        request.setCharacterEncoding("UTF-8");
        String eid = request.getParameter("eid");
        String ename = request.getParameter("ename");
        int salary = Integer.parseInt(request.getParameter("salary"));
        
        String driver = "oracle.jdbc.OracleDriver";
        String url = "jdbc:oracle:thin:@localhost:1521:XE";
        String id = "root";
        String password = "1234";
        
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            Class.forName(driver);
            con = DriverManager.getConnection(url, id, password);
        
            String sql = "update emp set ename = ?, salary = ? where eid = ?";
            pstmt = con.prepareStatement(sql);
            pstmt.setString(1, ename);
            pstmt.setInt(2, salary);
            pstmt.setString(3, eid);
            
            int count = pstmt.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (rs != null)
                    rs.close();
                if (pstmt != null)
                    pstmt.close();
                if (con != null)
                    con.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        response.setCharacterEncoding("UTF-8");
        response.sendRedirect("/select?eid=" + eid);
    }
    
}
cs
PrepareStatement 객체를 이용하면 SQL 문을 먼저 작성하고 나중에 필요한 데이터를 설정할 수 있다.
set 메소드를 이용해 인덱스에 값을 지정한다. 인덱스는 작성한 SQL 문에 있는 '?' 심벌의 순서를 의미한다. 
'?' 심벌 수와 set 메소드 수는 같아야 한다.

DML(Insert, Update, Delete) 쿼리 요청에는 executeUpdate 메소드를 사용하여 데이터를 처리하고 변경된 레코드의 개수를 얻는다.


+ Recent posts