클래스 로더란?
자바는 컴파일 타임이 아니라 런타임(바이트 코드를 실행할 때)에 클래스 로드하고 링크하고 이 동적 로드를 담당한느 부분이 JVM의 클래스 로더이다. 즉, 클래스 로더는 런타임 중에 JVM의 메소드 영역에 동적으로 Java 클래스를 로드하는 역할을 한다.
클래스 로더 3단계
- 로딩
- 자바 바이트 코드(.class)를 메소드 영역에 저장
- 각 자바 바이트 코드(.class)는 JVM에 의해 메소드 영역에 정보를 저장
- 링크
- 검증 : 읽어 들인 클래스가 자바 언어 명세 및 JVM 명세에 명시된 대로 잘 구성되어 있는지 검사
- 준비 : 클래스가 필요로 하는 메로리를 할당, 클래스에서 정의된 필드, 메소드, 인터페이스를 나태내는 데이터 구조를 준비
- 분석 : 심볼릭 메모리 레퍼런스를 메소드 영역에 있는 실제 레퍼런스로 교체
- 초기화
- 클래스 변수들을 적절한 값으로 초기화. 즉, static 필드들이 설정된 값으로 초기화
클래스 로더의 종류
- 부트르스랩 클래스 로더 : JVM 시작 시 가장 최초로 실행되는 클래스 로더. 자바 클래스를 도르할 수 있는 자바 자체의 클래스 로더와 최소한의 자바 클래스만을 로드.
Java8 - jre/lib/rt.jar 및 기타 핵심 라이브러리와 같은 JDK의 내부 클래스를 로드.
Java9이후 - 더 이상 /rt.jar가 존재하지 않으며, /lib 내에 모듈화되어 포함. ClassLoader 내 최상위 클래스들만 로드.
- 확장 클래스 로더 : 부트스트랩 클래스 로더를 부모로 갖는 클래스 로더. java.ext.dirs 환경 변수에 설정된 디렉토리의 클래스 파일을 로드, 이 값이 설정되어 있지 않은 경우 ${JAVA_HOME}/jre/lib/ext 에 있는 클래스 파일을 로드.
Java8 - URLClassLoader를 상속하며, jre/lib/ext 내 모든 클래스를 로드.
Java9 이후 - Platform Loader로 변경되었으며, BuiltinClassLoader를 상속.InnerStatic 클래스로 구현.
- 시스템 클래스 로더 : 자바 프로그램 실행 시 지정한 Classpath에 있는 클래스 파일 혹은 jar에 속한 클래스들을 로드. 사용자가 만든 .class 확장자 파일을 로드.
클래스 로더의 동작방식
- JVM의 메소드 영역에 클래스가 로드되어 있는지 확인.
- 메소드 영역에 클래스가 로드되어 있지 않은 경우, 시스템 클래스 로더에 클래스 로드를 요청.
- 시스템 클래스 로더는 확장 클래스 로더에 요철을 위임.
- 확장 클래스 로더는 부트스트랩 클래스 로더에 요청을 위임.
- 부트스트랩 클래스 로더는 부트스트랩 Classpath(JDK/JRE/LIB)에 해당 클래스가 있는지 확인. 크랠스가 존재하지 않는 경우 확장 클래스 로더에게 요청을 넘김.
- 확장 클래스 로더는 확장 Classpath(JDK/JRE/LIB/EXT)에 해당 클래스가 있는지 확인. 클래스가 존재하지 않을 경우 시스템 클래스 로더에게 요청을 넘김.
- 시스템 클래스 로더는 시스템 Classpath에 해당 클래스가 있는지 확인. 클래스가 존재하지 않는 경우 ClassNotFountException을 발생.
클래스 로더가 지켜야할 세가지 원칙
- 위임원칙
- 가시범위 원칙 : 하위 클래스 로더는 상위 클래스 로더가 로드한 클래스를 볼 수 있지만, 반대로 상위 클래스 로더는 하위 클래스 로더가 로드한 클래스를 알 수 없다. 이로 인해 java.lang.Object 클래스 등 상위 클래스 로더에서 로드한 클래스도 한위 클래스 로더인 시스템 클래스 로더 등에서 사용할 수 있다.
- 유일성의 원칙 : 하위 클래스 로더가 상위 클래스 로더에게 로드한 클래스를 다시 로드하지 않아야 한다는 원칙.
동적 클래스 로딩
- 로드 타임 동적 로딩 : 하나의 클래스를 로딩하는 과정에서 동적으로 다른 클래스를 로딩
HelloWorld.class -> java.lang.String, java.lang.System
public class HelloWorld {
public static void main(String[] args) {
System.out.println("안녕하세요!");
}
}
- 런타임 동적 로딩 : 코드를 실행하는 순간에 클래스를 로딩
Class.forName(args[0])
public class RuntimeLoading {
public static void main(String[] args) {
try {
Class cls = Class.forName(args[0]);
Object obj = cls.newInstance();
Runnable r = (Runnable) obj;
r.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
출처