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
    (String name, boolean resolve)
    throws ClassNotFoundException{

    // First check if the class is already loaded
    Class c = findLoadedClass(name);
    if (c == null) {
        try {
            if (parent != null) {
                c = parent.loadClass(name, false);
            } else {
                c = findBootstrapClass0(name);
            }
        } catch (ClassNotFoundException e) {
            // If still not found, then invoke
            // findClass to find the class.
            c = findClass(name);
        }
    }
    if (resolve) {
    resolveClass(c);
    }
    return c;


- 클래스로더는 이미 로드된 클래스를 찾을 수 없을 때, parent에게 물어본다.
- parent의 parent (...) 에서도 찾지 못하고 결국 findBootstrapClass0() 역시 실패하면 findClass() 메서드를 호출한다.
- findClass() 메서드의 디폴트 구현은 ClassNotFoundException을 던지는 것이다.

    protected Class<?> findClass(String name)
        throws ClassNotFoundException {
        throw new ClassNotFoundException(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?

Posted by 天下太平
,