클래스 로더란?

자바는 컴파일 타임이 아니라 런타임(바이트 코드를 실행할 때)에 클래스 로드하고 링크하고 이 동적 로드를 담당한느 부분이 JVM의 클래스 로더이다. 즉, 클래스 로더는 런타임 중에 JVM의 메소드 영역에 동적으로 Java 클래스를 로드하는 역할을 한다.


클래스 로더 3단계

  • 로딩
    • 자바 바이트 코드(.class)를 메소드 영역에 저장
    • 각 자바 바이트 코드(.class)는 JVM에 의해 메소드 영역에 정보를 저장
  • 링크
    • 검증 : 읽어 들인 클래스가 자바 언어 명세 및 JVM 명세에 명시된 대로 잘 구성되어 있는지 검사
    • 준비 : 클래스가 필요로 하는 메로리를 할당, 클래스에서 정의된 필드, 메소드, 인터페이스를 나태내는 데이터 구조를 준비
    • 분석 : 심볼릭 메모리 레퍼런스를 메소드 영역에 있는 실제 레퍼런스로 교체
  • 초기화
    • 클래스 변수들을 적절한 값으로 초기화. 즉, static 필드들이 설정된 값으로 초기화


클래스 로더의 종류

  1. 부트르스랩 클래스 로더 : JVM 시작 시 가장 최초로 실행되는 클래스 로더. 자바 클래스를 도르할 수 있는 자바 자체의 클래스 로더와 최소한의 자바 클래스만을 로드.

Java8 - jre/lib/rt.jar 및 기타 핵심 라이브러리와 같은 JDK의 내부 클래스를 로드.

Java9이후 - 더 이상 /rt.jar가 존재하지 않으며, /lib 내에 모듈화되어 포함. ClassLoader 내 최상위 클래스들만 로드.

  1. 확장 클래스 로더 : 부트스트랩 클래스 로더를 부모로 갖는 클래스 로더. java.ext.dirs 환경 변수에 설정된 디렉토리의 클래스 파일을 로드, 이 값이 설정되어 있지 않은 경우 ${JAVA_HOME}/jre/lib/ext 에 있는 클래스 파일을 로드.

Java8 - URLClassLoader를 상속하며, jre/lib/ext 내 모든 클래스를 로드.

Java9 이후 - Platform Loader로 변경되었으며, BuiltinClassLoader를 상속.InnerStatic 클래스로 구현.

  1. 시스템 클래스 로더 : 자바 프로그램 실행 시 지정한 Classpath에 있는 클래스 파일 혹은 jar에 속한 클래스들을 로드. 사용자가 만든 .class 확장자 파일을 로드.


클래스 로더의 동작방식

  1. JVM의 메소드 영역에 클래스가 로드되어 있는지 확인.
  2. 메소드 영역에 클래스가 로드되어 있지 않은 경우, 시스템 클래스 로더에 클래스 로드를 요청.
  3. 시스템 클래스 로더는 확장 클래스 로더에 요철을 위임.
  4. 확장 클래스 로더는 부트스트랩 클래스 로더에 요청을 위임.
  5. 부트스트랩 클래스 로더는 부트스트랩 Classpath(JDK/JRE/LIB)에 해당 클래스가 있는지 확인. 크랠스가 존재하지 않는 경우 확장 클래스 로더에게 요청을 넘김.
  6. 확장 클래스 로더는 확장 Classpath(JDK/JRE/LIB/EXT)에 해당 클래스가 있는지 확인. 클래스가 존재하지 않을 경우 시스템 클래스 로더에게 요청을 넘김.
  7. 시스템 클래스 로더는 시스템 Classpath에 해당 클래스가 있는지 확인. 클래스가 존재하지 않는 경우 ClassNotFountException을 발생.


클래스 로더가 지켜야할 세가지 원칙

  • 위임원칙
  • 가시범위 원칙 : 하위 클래스 로더는 상위 클래스 로더가 로드한 클래스를 볼 수 있지만, 반대로 상위 클래스 로더는 하위 클래스 로더가 로드한 클래스를 알 수 없다. 이로 인해 java.lang.Object 클래스 등 상위 클래스 로더에서 로드한 클래스도 한위 클래스 로더인 시스템 클래스 로더 등에서 사용할 수 있다.
  • 유일성의 원칙 : 하위 클래스 로더가 상위 클래스 로더에게 로드한 클래스를 다시 로드하지 않아야 한다는 원칙.


동적 클래스 로딩

  1. 로드 타임 동적 로딩 : 하나의 클래스를 로딩하는 과정에서 동적으로 다른 클래스를 로딩

HelloWorld.class -> java.lang.String, java.lang.System

public class HelloWorld { 
        public static void main(String[] args) { 
                System.out.println("안녕하세요!"); 
        } 
}


  1. 런타임 동적 로딩 : 코드를 실행하는 순간에 클래스를 로딩

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();
                }
        }
}


출처

https://steady-coding.tistory.com/593