java class loader #1
Java는 동적으로 클래스를 로딩하기 때문에 런타임에 모든 코드가 JVM에 링크됩니다. 모든 클래스는 해당 클래스가 참조되는 순간에 동적으로 JVM에 링크되며, 메모리에 로딩됩니다. 자바의 런타임 라이브러리([jdk path]/jre/lib/rt.jar) 역시 예외가 아닙니다. 이러한 동적인클래스 로딩은 자바의 클래스로더 시스템을 통해서 이루어지며, 자바가 기본적으로 제공하는 클래스로더는 java.lang.ClassLoader를 통해서 표현됩니다. JVM이 시작되면, 부트스트랩(bootstrap) 클래스로더를 생성하고, 그 다음에 가장 첫번째 클래스인 Object를 시스템에 로딩합니다.
런타임에 동적으로 클래스를 로딩한다는 것은 JVM이 클래스에 대한 정보를 갖고 있지 않다는 것을 의미함으로서 JVM은 클래스에 대한정보를 알지 못합니다. 따라서, 클래스로더는 클래스를 로딩할 때 필요한 정보를 구하고, 그 클래스가 올바른지를 검사해야 합니다.
Load-time dynamic loading and Run-time dynamic loading
클래스를 로딩하는 방식에는 로드타임 동적 로딩(load-time dynamic loading)과 런타임 동적 로딩(run-time dynamic loading)이 있습니다.
public class HelloWorld {
public static void main(String[] args) {
System.out.println("안녕하세요!");
}
}
코드 1.
로드타임 동적 로딩은 하나의 클래스를 로딩하는 과정에서 동적으로 클래스를 로딩하는 것을 말합니다. 코드 1의 HelloWorld 클래스를 실행하면, JVM이 시작되고, 앞에서 말했듯이 부트스트랩 클래스로더가 생성된 후에, 모든 클래스가 상속받고 있는 Object 클래스를 읽어옵니다. 그 이후에, 클래스로더는 명령행에서 지정한 HelloWorld 클래스를 로딩하기 위해 HelloWorld.class 파일을 읽습니다. 그리고HelloWorld 클래스를 로딩하는 과정에서 필요한 클래스 java.lang.String과 java.lang.System를 읽어옵니다. 이 두 클래스는 HelloWorld 클래스를 읽어오는 로드타임에 동적으로 로딩됩니다.
class HelloWorld1 implements Runnable {
public void run() {
System.out.println("안녕하세요, 1");
}
}
class HelloWorld2 implements Runnable {
public void run() {
System.out.println("안녕하세요, 2");
}
}
public class RuntimeLoading {
public static void main(String[] args) {
try {
if (args.length < 1) {
System.out.println("사용법: java RuntimeLoading [클래스 이름]");
System.exit(1);
}
Class klass = Class.forName(args[0]);
Object obj = klass.newInstance();
Runnable r = (Runnable) obj;
r.run();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
코드 2.
런타임 동적 로딩은 클래스를 로딩할 때가 아닌 코드를 실행하는 순간에 클래스를 로딩하는 것을 말합니다.
코드 2에서 Class.forName(className)은 파리미터로 받은 className에 해당하는 클래스를 로딩한 후에 그 클래스에 해당하는 로딩한 클래스의 인스턴스가 아닌 Class 인스턴스를 리턴합니다. 그리고 Class 클래스의 newInstance() 메소드는 Class가 나타내는 클래스의 인스턴스를 생성합니다. 예를 들어, 코드 3은 java.lang.String 클래스의 객체를 생성합니다.
Class klass = Class.forName("java.lang.String");
Object obj = klass.newInstance();
코드 3.
따라서, Class.forName() 메소드를 실행하는 클래스에서는 Class.forName()이 실행되기 전까지는 어떤 클래스를 참조하는 지 알 수 없습니다.
ClassLoader
클래스로더를 사용하기 위해서는 보통의 자바 클래스처럼 해당하는 클래스의 객체를 생성하고, 그 객체의 특정 메소드를 호출하면 됩니다. 또한, 상속을 받아 클래스로드를 커스터마이징 할 수도 있습니다.
자바의 클래스로더는 클래스로더 딜리게이션 모델(ClassLoader Delegation Model)으로서 부모 클래스로더가 먼저 클래스를 로딩하도록합니다. 즉, 특정 클래스로더 클래스를 읽어온 클래스로더(부모 클래스로더)에게 클래스 로딩을 요청하는 것입니다.
그림 1. ClassLoader Delegation Model[1]
그림 1은 클래스로더간의 관계를 보여주고 있습니다. 이 경우, NetworkClassLoader(가정)는 JarFileClassLoader(가정)가 로딩하고, JarFileClassLoader 클래스는 AppClassLoader가 로딩하였음을 보여줍니다. 즉, JarFileClassLoader는 NetworkClassLoader의 부모 클래스로더가 되고, AppClassLoader는 JarFileClassLoader의 부모 클래스로더가 되는 것입니다.
<자바에서 기본으로 제공하는 부트스트랩클래스로더 등에 관한 설명은 [2-3]를 보면 알 수 있습니다.>
References
[1] http://javacan.tistory.com/3
[2] http://blog.naver.com/PostView.nhn?blogId=choigohot&logNo=40192701035
[3] http://javacan.tistory.com/entry/2