Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

Java 9 클래스 로더의 주요 변경 사항 완벽 정리

모든 자바(Java) 프로그램은 자바 가상 머신(JVM) 위에서 실행됩니다. 소스 코드가 컴파일되면 자바 클래스는 플랫폼에 독립적이고 기계에 종속되지 않는 바이트코드(bytecode)로 변환되며, 컴파일된 클래스는 .class 파일 형태로 저장됩니다. 이후 프로그램이 해당 클래스를 사용하려고 할 때 클래스 로더(ClassLoader)가 그 클래스를 메모리에 적재합니다. 클래스는 이름으로 참조되는 시점에 자바 환경에 도입되며, main() 메서드는 클래스 실행의 시작점 역할을 합니다.

Java 9에서 달라진 클래스 로더 구조

Java 9에서는 모듈 시스템(JPMS)의 도입과 함께 클래스 로더 계층 구조에 몇 가지 중요한 변화가 생겼습니다. 주요 변경 사항은 다음과 같습니다.

  • 시스템 클래스 로더(System Class Loader): 더 이상 URLClassLoader의 인스턴스가 아니라 내부(internal) 클래스로 구현됩니다. 모듈에 포함된 클래스를 위한 기본 로더(default loader) 역할을 담당합니다.
  • 확장 클래스 로더 → 플랫폼 클래스 로더로 명칭 변경: 기존의 확장(Extension) 클래스 로더는 플랫폼 클래스 로더(Platform Class Loader)로 이름이 바뀌었습니다. Java SE 플랫폼의 모든 클래스는 플랫폼 클래스 로더를 통해 확인할 수 있으며, JCP(Java Community Process) 산하 모듈 중 Java SE 플랫폼에는 속하지 않는 클래스 역시 플랫폼 클래스 로더를 통해 접근 가능합니다.
  • 애플리케이션은 특정 클래스 로더에 의존할 수 없음: Java SE 플랫폼의 일부 클래스는 플랫폼 클래스 로더가 정의하고, 나머지는 부트스트랩 클래스 로더(Bootstrap Class Loader)가 정의합니다. 따라서 애플리케이션이 "특정 클래스가 어느 로더에 의해 정의되는가"에 의존하는 설계는 지양해야 합니다.
  • 부모 로더 지정 방식 변경 필요: 기존 코드에서 부트스트랩 클래스 로더를 부모(parent)로 지정하여 클래스 로더를 생성했다면, 플랫폼 클래스 로더를 부모로 사용하도록 수정해야 합니다.
  • 플랫폼 클래스 로더 역시 내부 클래스: 플랫폼 클래스 로더 또한 URLClassLoader의 인스턴스가 아니라 JVM 내부 클래스로 구현되어 있습니다.
  • 부트스트랩 클래스 로더: JVM의 내장(built-in) 클래스 로더로, java.base와 같은 핵심 모듈의 클래스들을 정의합니다. -Xbootclasspath/a 옵션으로 배포하거나 부모를 null로 지정해 클래스 로더를 생성하는 애플리케이션은 코드 변경이 필요할 수 있습니다.

예제 코드

아래 예제는 서로 다른 클래스들이 어떤 클래스 로더에 의해 적재되는지 확인하는 간단한 테스트입니다.

public class ClassLoaderTest {
    public static void main(String args[]) {
        System.out.println("Class Loader Test");
        ClassLoaderTest test = new ClassLoaderTest();
        try {
            test.showClassLoaders();
        } catch(ClassNotFoundException cnfe) {
            System.out.println(cnfe.getMessage());
        }
    }
    public void showClassLoaders() throws ClassNotFoundException {
        System.out.println("Classloader of this class: " + ClassLoaderTest.class.getClassLoader());
        System.out.println("Classloader of Permission: " + java.sql.SQLPermission.class.getClassLoader());
        System.out.println("Classloader of LinkedList: " + java.util.LinkedList.class.getClassLoader());
        return;
    }
}

실행 결과

Class Loader Test
Classloader of this class: jdk.internal.loader.ClassLoaders$AppClassLoader@504bae78
Classloader of Permission: jdk.internal.loader.ClassLoaders$PlatformClassLoader@299a06ac
Classloader of LinkedList: null

결과 해석

  • ClassLoaderTest: 사용자가 작성한 애플리케이션 클래스이므로 AppClassLoader(시스템/애플리케이션 클래스 로더)가 적재합니다.
  • java.sql.SQLPermission: Java SE 플랫폼의 모듈에 속한 클래스로, PlatformClassLoader가 적재합니다.
  • java.util.LinkedList: java.base 등 핵심 모듈의 클래스로 부트스트랩 클래스 로더가 적재하며, 부트스트랩 로더는 네이티브로 구현되어 있어 getClassLoader() 호출 시 null이 반환됩니다.

이처럼 Java 9부터는 클래스 로더의 구현 방식과 계층 구조가 모듈 시스템에 맞춰 재편되었으므로, 기존에 클래스 로더 내부 동작에 의존하던 코드는 반드시 호환성을 검토해야 합니다.