2012-06-29 3 views
1

아래의 테스트 케이스. 출력 : 출력의 두 번째와 세 번째 선 사이 표시 :Java에서 클래스 분석을 위해 클래스 로더를 사용하는 방법

custom loading of: pkg.TestRun 
ran. 
wish this would run in my custom classloader 

내가 일이 원하는 것은 "pkg.TestRun 사용자 정의로드"를 참조하는 것입니다.

부모로부터 첫 번째 클래스가로드 된 경우에도 내 맞춤 클래스 로더에서 클래스의 종속성을로드하려면 어떻게해야합니까? 내 실제 사례에서, OtherClass에 상응하는 것이 상위 클래스 로더에 알려지지 않았기 때문에 예외가 발견되지 않습니다.

한 가지 해결책은 사용자 지정 클래스 로더가 TestRun을 명시 적으로로드하는 것입니다. 그러나 TestRun을로드하는 방법은 이미 부모 클래스 로더에 알려져 있으며, 이미 완료되었으므로 별도로 찾기를 관리하고 싶지 않습니다. 내가하지 않고 이미 관리되고있을 때 어떻게 든 알아낼 수는 있습니다. 아무것도. 그리고 나는 super.getResource (null 반환) 또는 findClass (이미 부모 클래스를 클래스로 설정)와 같은 작업을 시도했지만 어느 것도 작동하지 않았습니다.

그렇다면 부모가 클래스를 찾을 수 있도록 할 수는 있지만 사용자 정의 로더가 클래스를 정의 할 수 있습니까? 또는, 의존성을 찾기 위해 항상 내 커스텀 로더를 사용할 수 있도록하는 방법이 있습니까?

package pkg; 

public class TestCL { 

    static class MyCL extends ClassLoader { 
     MyCL(ClassLoader parent) { 
      super(parent); 
     } 

     @Override 
     public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { 
      System.out.println("custom loading of: " + name); 
      return getParent().loadClass(name); 
     } 
    } 

    public static void main(String[] args) throws Exception { 
     MyCL cl = new MyCL(Thread.currentThread().getContextClassLoader()); 
     Thread.currentThread().setContextClassLoader(cl); 
     cl.loadClass("pkg.TestRun").getMethod("run", new Class[] {}).invoke(null); 
    } 
} 

class TestRun { 
    public static void run() { 
     System.out.println("ran."); 
     OtherClass.runAlso(); 
    } 
} 

class OtherClass { 
    public static void runAlso() { 
     System.out.println("wish this would run in my custom classloader"); 
    } 
} 
+0

왜 사용자 정의 클래스 로더가 필요하다고 생각하십니까? – duffymo

+0

'-verbose : class' 명령 행 옵션은 클래스 로딩 문제를 디버깅 할 때 당신의 친구입니다. – biziclop

+0

'OtherClass의 사용자 정의로드'를 보시겠습니까? 기본 클래스 로더에서 OtherClass를로드하는 것을 찾기 위해 디버거를 사용할 것입니다. – davidfrancis

답변

0

하나의 솔루션은, 클래스의 바이트를 읽어 부모 클래스 로더 (또는 어디 있는지 이미 알고있는 하나)를 사용하여 사용자 지정에서 그것을 정의하는 것입니다 클래스 로더.

그래서,이 같은 :

public static byte[] loadBytesForClass(ClassLoader loader, String fqn) throws IOException { 
    InputStream input = loader.getResourceAsStream(fqn.replace(".", "/") + ".class"); 
    if (input == null) { 
     System.out.println("Could not load bytes for class: " + fqn); 
    } 
    ByteArrayOutputStream output = new ByteArrayOutputStream(); 
    StringUtil.copy(input, output); 
    return output.toByteArray(); 
} 

그런 다음 당신은 사용자 정의 클래스 로더를 정의하는 바이트 defineClass(name, bytes, 0, bytes.length)를 호출 할 수 있습니다.

0

문제는 당신이 그것은 클래스를로드 할 부모를 요청
사용자 정의 클래스 로더를 사용하여 아무것도로드되지 않은, 그래서 모든 메인 클래스 로더에 의해로드되고 있었다. 그것은 다른 클래스 로더에 패키지 개인 있다는 그렇지 않으면 액세스 할 수 캔트,

package stackoverflow.june2012.classloader; 

import java.io.File; 
import java.net.URL; 
import java.net.URLClassLoader; 

public class TestCL { 

static class MyCL extends URLClassLoader { 
    MyCL(URL[] urls) { 
     // NOTE: No parent classloader! 
     super(urls, null); 
    } 

    @Override 
    public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { 
     System.out.println("custom loading of: " + name); 
     return super.loadClass(name, resolve); 
    } 

    @Override 
    protected Class<?> findClass(String name) throws ClassNotFoundException { 
     System.out.println("findClass: " + name); 
     System.out.println("NOTE: Only called if this classloader does NOT have a parent"); 
     return super.findClass(name); 
    } 
} 

public static void main(String[] args) throws Exception { 
    URL url = new File("./bin").toURI().toURL(); 
    System.out.println("url to search for classes: " + url); 
    MyCL cl = new MyCL(new URL[] {url}); 
    Thread.currentThread().setContextClassLoader(cl); 
    Class loadClass = cl.loadClass("stackoverflow.june2012.classloader.TestRun"); 
    System.out.println("Loaded TestRun using classloader: " + loadClass.getClassLoader()); 
    loadClass.getMethod("run", new Class[] {}).invoke(null); 
} 

}

그리고 별도의 파일로 다른 2 개 종류를 이동했다 :

이 수정 된 코드를 사용해보십시오 :

package stackoverflow.june2012.classloader; 

public class TestRun { 
    public static void run() { 
    System.out.println("ran."); 
    OtherClass.runAlso(); 
    } 
} 

class OtherClass { 
    public static void runAlso() { 
     System.out.println("wish this would run in my custom classloader"); 
    } 
} 
+0

에 의해로드되는 이유를 보여줍니다. TestRun을 찾을 수있는 URL을 알고 있어야합니다. "필자는 하나의 해결책은 맞춤 클래스 * 로더가 TestRun을 명시 적으로로드하는 것임을 알고 있지만, 이미 부모 클래스 로더에게 알려져 있으므로 찾아야 할 필요가 없습니다. 그것은 이미 완료 되었기 때문에 별도로. " 내가 실수 한 것을 볼 수는 있지만 (* added loader *) 거기에 내가 지금 고쳐 놓았다. – mentics

+0

오, 무슨 뜻인지 알 겠어.나는 대답이 "아니오"라고 생각한다. 모든 작업을 수행하려면 사용자 정의 클래스 로더를 가져야합니다. 클래스 로더가 클래스를로드 한 경우, 내가 아는 한 모든 의존성을로드합니다. URL을 찾는 것은 여러 가지 방법으로 수행 할 수 있습니다. 필자는 예제를 통해 매우 쉬운 방법으로이를 수행했습니다. 실제 코드의 경우, 예를 들어 알려진 .class 파일을 스캔하고 그로부터 사용자 정의 클래스 로더의 URL을 구성 할 수 있습니다. – davidfrancis

관련 문제