시스템 ClassLoader가 런타임에 지정된 .class 파일을 로드하도록 하는 것이 가능합니까?
-
18-09-2019 - |
문제
과제에 대한 정적 분석 도구를 작성 중인데 ASM 라이브러리를 사용하여 Java 바이트코드를 분석합니다.우리가 사용하는 ASM 부분 중 하나는 클래스가 ClassLoader에서 로드되도록 요구합니다(또는 적어도 요구하는 것처럼 보입니다).
우리는 이 도구가 클래스 경로에 파일을 요구하지 않고도 .class 파일을 분석할 수 있기를 바랐습니다.우리는 이미 런타임에 지정된 디렉터리에서 .classes를 로드하고 InputStream을 사용하여 읽습니다.이는 대부분의 경우 ASM에 허용됩니다.등의 수업이 있습니다. SimpleVerifier
, 클래스를 로드하려고 시도합니다.
이 시나리오에서 로드할 .class 파일을 등록하여 다음을 호출하는 것이 가능합니까? Class.forName()
로드할래?아니면 이를 허용하도록 ClassLoader를 확장하는 쉬운 방법이 있습니까?
편집하다:에 대한 정보 URLClassLoader
유용했습니다.불행히도, Thread.currentThread().setContextClassLoader()
이 시나리오에서는 그 인스턴스가 작동하지 않았습니다.내가 호출하는 라이브러리 코드는 다음을 사용하여 인스턴스 초기화 시 검색하는 로더를 사용합니다. getClass().getClassLoader()
.
URLClassLoader를 설정할 때쯤에는 클래스가 초기화되지 않았으므로 contextClassLoader가 해당 클래스를 로드하지 않는 것 같습니다.
내가 응답을 올바르게 이해했는가?제3자 클래스를 로드하기 위해 URLClassLoader를 사용할 수 있습니까?
해결책
거의.
어딘가에 수업을 컴파일 한 경우 UrlClassloader. 그런 다음이 클래스 로더를 현재 스레드의 클래스 로더로 설정할 수 있습니다. Thread.SetContextClassLoader (클래스 로더)
사용자는 현재 스레드 컨텍스트 클래스 로더를 얻고 클래스 정의에 액세스하는 데 사용할 수 있습니다.
다른 팁
우선, ASM은 클래스에 대한 정보를 얻기 위해 클래스 로더를 사용하지 않는 방식으로 사용할 수 있습니다.
ASM 프레임 워크에는 기본적으로 클래스를로드하는 여러 장소가 있지만 모든 장소는 자신의 하위 클래스에서 무시할 수 있습니다. 내 머리 꼭대기에서 :
- classwriter.getCommonSuperClass () 메소드는 classwriter.compute_frames 플래그를 사용하는 경우에만 호출되며 클래스에 대한 정보를 얻기 위해 클래스 로더를 사용하지 않도록 덮어 쓸 수 있습니다. 그 예를 찾을 수 있습니다 ClasswriterComputeFramestest 그것은 classinfo 추상화를 소개합니다
- 유사하게 SimpleVerifier.getClass () 메소드가 사용합니다 simpleverifier.isassignablefrom () 또한 후자를 덮어 쓰고 ClassInfo 추상화를 사용하여 공통 수퍼 유형을 찾을 수 있습니다. 내가 실수하지 않으면 Sagewerkz Project는 유형 패턴 일치 코드에서 비슷한 것을 구현했습니다. 또한 있습니다 simpleverifier.setclassloader () 자신의 클래스를로드하려는 경우 사용할 수있는 방법.
참고로, 태양의 JVMS에서로드 된 클래스는 Permgen 영역에 도달하여 언로드 할 수 없으므로, 피할 수있는 경우, 특히 공구가 도구가 될 경우에만 정적 코드 분석 목적으로 만 클래스를로드하는 것이 좋지 않습니다. IDE와 같은 오랜 프로세스에 통합됩니다.
내가 아는 한, 런타임에 시스템 클래스 로더를 확장 할 수는 없지만, 임의 위치 (JAR 또는 디렉토리)에서 클래스를 동적으로로드 할 수 있습니다. UrlClassloader.
애플리케이션을 시작할 때 "런처"를 설정해 볼 수 있습니다. URLClassLoader
클래스 경로와 자신의 위치를 전달합니다. .class
해당 클래스로더에서 애플리케이션을 시작합니다.
때 SimpleVerifier
에 의해 로드됩니다. URLClassLoader
또한 추가 위치에서 클래스를 로드할 수도 있습니다.
예, 사용할 수 있습니다 UrlClassloader
런타임에 클래스를로드하는 테스트가 있습니다. 이 클래스는 클래스 경로에 있지 않으며 (그 문제에 대해 테스트가 실행될 때도 존재하지도 않습니다) 나중에로드되고 훌륭합니다.
코드는 다음과 같습니다.
void testHello() throws MalformedURLException, ClassNotFoundException {
URL[] url = {
new URL("file:/home/oreyes/testwork/")
};
try {
new URLClassLoader(url).loadClass("Hello");
throw new AssertionError("Should've thrown ClassNotFoundException");
} catch ( ClassNotFoundException cnfe ){}
c.process();// create the .class file
new URLClassLoader(url).loadClass("Hello");
// it works!!
}
이것에서 가져 왔습니다 의문.
나는 내 자신의 클래스 로더를 아주 간단하게 만들었습니다.
/**
* Used to hold the bytecode for the class to be loaded.
*/
private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();
@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
final byte[] bytes = BYTE_CODE.get();
if (null == bytes) {
throw new ClassNotFoundException(name);
}
return this.defineClass(null, bytes, 0, bytes.length);
}