.java
확장자인 파일은 자바언어로 소스 코드를 작성할 때 사용.class
확장자인 파일은 자바 컴파일러로 컴파일 한 파일JVM
에 로딩한다.Java는 동적 로딩을 지원하기 때문에 모든 클래스를 로딩하지 않고 필요한 시점에 클래스를 로딩하여 사용할 수 있다.
로드타임 동적 로딩은 클래스를 로딩할 때 필요한 다른 클래스를 동적으로 로딩하는 것이다.
예를 들어, System.out.println("Hello World");
와 같은 코드가 작성되어 있는 Hello.java
를 Hello.class
로 컴파일 하고 JVM에 로딩한다고 생각해보자.
이때 필요한 System
, String
관련 .class 파일도 같이 로딩한다.
말 그대로 "로드 타임 동적로딩" 이다.
런타임 동적 로딩은 코드를 실행하는 순간 클래스를 로딩하는 것이다.
즉 JVM이 코드를 실행하다가 .class 파일을 로딩하는 것을 의미한다.
여기서 이번 주제인 Class.forName("로드할 클래스 이름")
이 사용된다.
아래의 예는 토비의 스프링에서 나온 JDBC API 사용하여 DB연결을 하는 예 중 일부를 가져온 것이다.
public class UserDao{
public void add(User user) throws ClassNotFindException, SQLExcption{
Class.forName("com.mysql.jdbc.Driver");
Connection c = DriverManager.getConnection(
"jdbc:mysql://localhost/springbook","spring","book"
);
//...
}
}
add 메서드가 실행될때 동적으로 Driver를 로딩한다.
그런데 이상하다. Class.forName()
의 리턴값도 받지 않는데 어떻게 커넥션을 사용할 수 있을까?
Driver 클래스의 구조이다. (자손으로 oracle.jdbc.driver.OracleDriver
, com.mysql.jdbc.Driver
등을 가지고 있음)
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
그외 기타 기능
}
보면 static{} 구문이 들어있다.
이는 클래스가 로드 될때 실행되는 구문으로, 여기서는 DriverManager에 Driver을 등록하는 구문이 쓰여있다.
즉 런타임 동적 로딩을 통해 클래스가 로딩되면 DriverManager에 Driver가 등록되는 구조이다.
그렇다면 왜 처음 클래스가 로드될때 로드하지 않고 메서드 단에서 로드를 하는 것일까?
(물론 OracleDriver oracleDriver=new OracleDriver();
이런식으로 로드타임 동적 로딩을 해도 정상 작동한다.)
하지만 저렇게 new를 사용해서 로드하게 되면, 의미없는 객체 1개를 생성해서 메모리 낭비를 하고 있다. 결국 DriverManager을 통해 사용하기 때문이다.
또 다른 이유는
String dirverName=request.getParameter("driverName");
String connectionInfo="";
if(dirverName.equals("oracle.jdbc.driver.OracleDriver")){
connectionInfo="jdbc:oracle:thin:@127.0.0.1:1521:xe";
}else{
//오라클 말고 기타 DB Driver
}
try{
Class.forName(dirverName);
}catch (ClassNotFoundException e){
//에러처리하는 코드
}
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
try{
conn=DriverManager.getConnection(connectionInfo,"jsp","oracle");
stmt=conn.createStatement(); //쿼리 수행
rs=stmt.executeQuery("SELECT 1 FROM DUAL");
if(rs.next()) System.out.print(rs.getInt(1));
}catch (SQLException e){
//에러처리하는 코드
}finally {
if(rs!=null){try{rs.close();} catch(Exception e){} }
if(stmt!=null){try{stmt.close();} catch(Exception e){} }
if(conn!=null){try{conn.close();} catch(Exception e){} }
}
이 코드를 보면, 파라미터 값에 따라 oracle, mysql같은 다양한 드라이버에 연결하게 됩니다.
만약 여기서 로드타임 동적로딩을 사용하게 되면, 로드되는 순간 그 수많은 드라이버를 한번에 로드하고 들고 있게 됩니다.
하지만 Class.getName()
을 사용하면 딱 사용하는 순간에 로드할 수 있게된다.
정리하면 Class.forName()을 쓰는 이유는
1. Driver의 경우 로드만 하면 되지 객체 생성은 필요 없다.
2. 특정 조건에 따라 Driver로드 다르게 할 때는 모든 Driver을 미리 로드할 필요없다.