Java Language
클래스 로더
수색…
비고
클래스 로더는 응용 프로그램이 사용하는 클래스의 위치와 로딩을 중재하는 것을 주 목적으로하는 클래스입니다. 클래스 로더는 또한 자원을 찾아로드 할 수 있습니다.
표준 클래스 로더 클래스는 파일 시스템의 디렉토리와 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)
-이 메서드를 오버로드하여 대체 위임 모델을 구현합니다. -
findResource
및findResources
- 이러한 메소드를 오버로드하여 리소스로드를 사용자 정의합니다.
실제로 바이트 배열에서 클래스를로드하는 역할을하는 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
가 호출 될 때 다음과 같이 동작합니다.
- 클래스 로더의
loadClass
메소드는findLoadedClass
를 호출하여이 클래스 로더가이 클래스 로더에 의해 이미로드되었는지 여부를 확인합니다. 성공했을 경우, 결과의Class
객체가 요구자가 돌려 주어집니다. -
loadClass
메소드는loadClass
호출을 호출하여 상위 클래스 로더에 위임합니다. 부모가 요구를 처리 할 수있는 경우는Class
오브젝트를 돌려 주어, Requestor에게 돌려 주어집니다. - 부모 클래스 로더가 클래스를로드 할 수없는 경우
findClass
다음 우리의 재정의 호출findClass
클래스의 이름을로드 할 전달 방법을. - 요청 된 이름이
this.classname
과 일치this.classname
defineClass
를 호출하여this.classfile
바이트 배열에서 실제 클래스를로드합니다. 결과의Class
오브젝트가 돌려 주어집니다. - 이름이 일치하지 않으면
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();
}