http://onjava.com/pub/a/onjava/2005/01/26/classloading.html
Internals of Java Class Loading
by Binildas Christudas
01/26/2005
Class and Data
- class = code, data = state
- 모든 클래스는 java.lang.Class 의 인스턴스 형태로 code를 가진다
- 컴파일러는 class라는 이름의 public static final 필드를 모든 클래스에 삽입한다.
public static final Class class;
- JVM이 클래스를 한 번 로드하면, 같은 클래스는 다시 로드되지 않는다.
- 여기서 같은 클래스는 fully qualified name (package name + class name)으로 구별된다.
- JVM에서 fully qualified name과 그 클래스를 로드한 ClassLoader를 함께 사용하여 하나의 고유한 클래스를 식별한다.
- 어떤 클래스를 C1, 패키지를 Pg, 클래스로더 인스턴스를 Kl1 이라고 할 때,
- JVM에서 (C1, Pg, Kl1)이 C1이라는 클래스의 키이다.
- 즉, (C1, Pg, Kl1)과 (C1, Pg, Kl2)는 같은 클래스가 아니다.
Class Loaders
- JVM에서 모든 클래스는 어떤 java.lang.ClassLoader의 인스턴스에 의해 로드된다.
- java.lang.Object 와 기본 클래스들은 bootstrap class loader에 의해 로드된다.
- 이 기본 클래스들은 JRE/lib/rt.jar라는 파일로 패키징된다.
- boot class loader는 natively implementation 된다. JVM마다 구현은 다르다.
- 다음과 같이 core java runtime 클래스의 클래스로더를 얻으려고 하면 null을 얻게된다.
log(java.lang.String.class.getClassLoader());
- java.ext.dirs property로 얻어지는 경로에서 extension 라이브러리를 찾을 수 있다.
- 이 경로의 모든 jar 파일은 ExtClassLoader에 의해 로드된다.
- 개발자 관점에서 가장 중요한 세번째의 클래스로더는 AppClassLoader이다.
- java.class.path property로 얻어지는 경로의 클래스들은 AppClassLoader에 의해 로드된다.
이곳이 CLASSPATH이다.
- java.lang.Thread는 public ClassLoader getContextClassLoader()를 포함한다.
- 이것은 context class loader를 리턴한다.
- context class loader는 Thread를 생성한 코드에 의해 제공된다.
- Thread에 의해 실행되는 코드가 클래스나 리소스를 로드할 때 사용된다.
How Class Loaders Work
- bootstrap class loader를 제외한 모든 클래스로더는 parent 클래스로더를 갖는다.
- 모든 클래스로더의 타입은 java.lang.ClassLoader이다.
- 모든 클래스로더의 parent 클래스로더는 그 클래스로더를 로드한 클래스로더이다.
- 클래스로더의 loadClass() 메서드를 사용하여 클래스로더에게 클래스를 요청한다.
- loadClass() 메서드 내부동작은 다음과 같다. (from java.lang.ClassLoader 의 소스코드)
protected synchronized Class<?> loadClass |
- 클래스로더는 이미 로드된 클래스를 찾을 수 없을 때, parent에게 물어본다.
- parent의 parent (...) 에서도 찾지 못하고 결국 findBootstrapClass0() 역시 실패하면 findClass() 메서드를 호출한다.
- findClass() 메서드의 디폴트 구현은 ClassNotFoundException을 던지는 것이다.
protected Class<?> findClass(String name) |
- 커스텀 클래스로더를 구현하는 개발자는 이 메서드를 구현하게 된다.
- findClass() 의 내부에서 클래스로더는 임의의 소스로부터 바이트코드를 얻어온다.
- 여기서 임의의 소스는 filesystem, network URL, database, 혹은 다른 어플리케이션일 수 있다.
- 바이트코드를 얻은 후에 findClass() 메서드는 defineClass() 메서드를 호출해야 한다. (바이트코드를 Class로 변환)
- 자바 런타임은 어떤 클래스로더 인스턴스가 defineClass()를 호출했는지를 구별한다.
- 두 개의 클래스로더 인스턴스가 같은 소스의 바이트코드를 define 하더라도, 두 개의 클래스는 다른 클래스이다.
The Java language specification gives a detailed explanation on the process of loading, linking, and the initialization of classes and interfaces in the Java Execution Engine.
- Figure 1
- 다른 클래스로더에서 로드된 (같은 바이트코드의) 클래스를 대입하려고 하는 경우 ClassCastException이 발생한다.
A more detailed explanation on the process of class loading, defining, and linking is in Andreas Schaefer's article "Inside Class Loaders."
Why Do We Need our Own Class Loaders?