수색…


비고

클래스 로더는 응용 프로그램이 사용하는 클래스의 위치와 로딩을 중재하는 것을 주 목적으로하는 클래스입니다. 클래스 로더는 또한 자원을 찾아로드 할 수 있습니다.

표준 클래스 로더 클래스는 파일 시스템의 디렉토리와 JAR 및 ZIP 파일에서 클래스와 자원을로드 할 수 있습니다. 또한 원격 서버에서 JAR 및 ZIP 파일을 다운로드하고 캐시 할 수 있습니다.

클래스 로더는 일반적으로 연결되어 있으므로 JVM은 응용 프로그램 제공 소스보다 표준 클래스 라이브러리의 클래스를로드하려고 시도합니다. 사용자 정의 클래스 로더를 사용하여 프로그래머가이를 변경할 수 있습니다. 또한 바이트 코드 파일의 암호 해독 및 바이트 코드 수정과 같은 작업을 수행 할 수 있습니다.

클래스 로더 인스턴스화 및 사용

이 기본 예제는 애플리케이션이 클래스 로더를 인스턴스화하고이를 사용하여 클래스를 동적으로로드하는 방법을 보여줍니다.

URL[] urls = new URL[] {new URL("file:/home/me/extras.jar")};
Classloader loader = new URLClassLoader(urls);
Class<?> myObjectClass = loader.findClass("com.example.MyObject");

이 예제에서 생성 된 클래스 로더는 기본 클래스 로더를 부모로 가지며 "extra.jar"를보기 전에 부모 클래스 로더에서 모든 클래스를 먼저 찾습니다. 요청 된 클래스가 이미로드 된 경우 findClass 호출은 이전에로드 된 클래스에 대한 참조를 반환합니다.

findClass 호출은 다양한 방법으로 실패 할 수 있습니다. 가장 일반적입니다 :

  • 지정된 클래스를 찾을 수없는 경우 ClassNotFoundException 을 throw하여 호출합니다.
  • 명명 된 클래스가 발견되지 않는 다른 클래스에 종속되면 호출은 NoClassDefFoundError 를 throw합니다.

사용자 정의 classLoader 구현하기

모든 사용자 정의 로더는 java.lang.ClassLoader 클래스를 직접 또는 간접적으로 확장해야합니다. 주요 확장 점 은 다음과 같은 방법입니다.

  • findClass(String) - 클래스 로딩이 클래스 로딩을위한 표준 위임 모델을 따르는 경우이 메서드를 오버로드합니다.
  • loadClass(String, boolean) -이 메서드를 오버로드하여 대체 위임 모델을 구현합니다.
  • findResourcefindResources - 이러한 메소드를 오버로드하여 리소스로드를 사용자 정의합니다.

실제로 바이트 배열에서 클래스를로드하는 역할을하는 defineClass 메서드는 오버로드를 방지하기 위해 final 메서드입니다. 모든 사용자 정의 비헤이비어는 defineClass 를 호출하기 전에 수행해야합니다.

다음은 바이트 배열에서 특정 클래스를로드하는 간단한 예제입니다.

public class ByteArrayClassLoader extends ClassLoader {
    private String classname;
    private byte[] classfile;

    public ByteArrayClassLoader(String classname, byte[] classfile) {
        this.classname = classname;
        this.classfile = classfile.clone();
    }

    @Override
    protected Class findClass(String classname) throws ClassNotFoundException {
        if (classname.equals(this.classname)) {
            return defineClass(classname, classfile, 0, classfile.length);
        } else {
            throw new ClassNotFoundException(classname);
        }
    }
}

findClass 메소드 만 재정의했기 때문에이 사용자 정의 클래스 로더는 loadClass 가 호출 될 때 다음과 같이 동작합니다.

  1. 클래스 로더의 loadClass 메소드는 findLoadedClass 를 호출하여이 클래스 로더가이 클래스 로더에 의해 이미로드되었는지 여부를 확인합니다. 성공했을 경우, 결과의 Class 객체가 요구자가 돌려 주어집니다.
  2. loadClass 메소드는 loadClass 호출을 호출하여 상위 클래스 로더에 위임합니다. 부모가 요구를 처리 할 수있는 경우는 Class 오브젝트를 돌려 주어, Requestor에게 돌려 주어집니다.
  3. 부모 클래스 로더가 클래스를로드 할 수없는 경우 findClass 다음 우리의 재정의 호출 findClass 클래스의 이름을로드 할 전달 방법을.
  4. 요청 된 이름이 this.classname 과 일치 this.classname defineClass 를 호출하여 this.classfile 바이트 배열에서 실제 클래스를로드합니다. 결과의 Class 오브젝트가 돌려 주어집니다.
  5. 이름이 일치하지 않으면 ClassNotFoundException 을 던집니다.

외부 .class 파일로드

클래스를로드하려면 먼저 클래스를 정의해야합니다. 클래스는 ClassLoader 의해 정의됩니다. 한 가지 문제가 있습니다. 오라클은이 기능을 사용할 수있는 ClassLoader 코드를 작성하지 않았습니다. 클래스를 정의하려면 ClassLoader 의 private 메소드 인 defineClass() 메소드에 액세스해야합니다.

이 클래스에 액세스하려면 새로운 클래스 인 ByteClassLoader 를 만들어 ClassLoader 확장해야합니다. 클래스를 ClassLoader 확장 했으므로 ClassLoader 의 private 메서드에 액세스 할 수 있습니다. defineClass() 사용 가능하게 만들기 위해 우리는 private defineClass() 메소드의 미러처럼 동작 할 새로운 메소드를 생성 할 것입니다. 우리는 클래스 이름, 필요합니다 개인 메서드를 호출하려면 name , 클래스 바이트 classBytes 됩니다 첫 번째 바이트의 오프셋을, 0 하기 때문에 classBytes '데이터에서 시작 classBytes[0] , 그리고 마지막 바이트의 오프셋 (offset)하는 될 것입니다, classBytes.lenght 는 데이터의 크기를 나타내므로 마지막 오프셋이됩니다.

public class ByteClassLoader extends ClassLoader {

    public Class<?> defineClass(String name, byte[] classBytes) {
        return defineClass(name, classBytes, 0, classBytes.length);
    }

}

이제 public defineClass() 메소드가 있습니다. 클래스의 이름과 클래스 바이트를 인수로 전달하여 호출 할 수 있습니다.

stackoverflow 패키지에 MyClass 라는 클래스가 있다고 가정 해 봅시다.

메소드를 호출하려면 클래스 바이트가 필요하므로 Paths.get() 메소드를 사용하고 바이너리 클래스의 경로를 인수로 전달하여 클래스 경로를 나타내는 Path 객체를 만듭니다. 이제 클래스 바이트를 Files.readAllBytes(path) 가져올 수 있습니다. 그래서 우리는 ByteClassLoader 인스턴스를 만들고 우리가 만든 메소드 인 defineClass() 합니다. 우리는 이미 클래스 바이트를 가지고 있지만 우리의 메소드를 호출하기 위해 클래스 명 (이 경우에는 stackoverflow.MyClass )을 패키지 이름 (점)으로 제공해야한다.

Path path = Paths.get("MyClass.class");

ByteClassLoader loader = new ByteClassLoader();
loader.defineClass("stackoverflow.MyClass", Files.readAllBytes(path);

참고 : defineClass() 메서드는 Class<?> 객체를 반환합니다. 원하는 경우 저장할 수 있습니다.

클래스를로드하려면 loadClass() 호출하고 클래스 이름을 전달하면됩니다. 이 메소드는 ClassNotFoundException 던질 수 있으므로 try cath 블록을 사용해야한다.

try{
    loader.loadClass("stackoverflow.MyClass");
} catch(ClassNotFoundException e){
    e.printStackTrace();
}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow