-
26-09-2019 - |
質問
私は、実行時にクラスローダを切り替えるしようとしています:
public class Test {
public static void main(String[] args) throws Exception {
final InjectingClassLoader classLoader = new InjectingClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
Thread thread = new Thread("test") {
public void run() {
System.out.println("running...");
// approach 1
ClassLoader cl = TestProxy.class.getClassLoader();
try {
Class c = classLoader.loadClass("classloader.TestProxy");
Object o = c.newInstance();
c.getMethod("test", new Class[] {}).invoke(o);
} catch (Exception e) {
e.printStackTrace();
}
// approach 2
new TestProxy().test();
};
};
thread.setContextClassLoader(classLoader);
thread.start();
}
}
と
public class TestProxy {
public void test() {
ClassLoader tcl = Thread.currentThread().getContextClassLoader();
ClassLoader ccl = ClassToLoad.class.getClassLoader();
ClassToLoad classToLoad = new ClassToLoad();
}
}
(のInjectingClassLoader がのorg.apache.bcel.util.ClassLoader を継承したクラスである彼らのためにそれの親を尋ねる前に、クラスの修正バージョンをロードする必要があります)
私は「アプローチ1」及び「アプローチ2」とまったく同じ結果をしたいのですが、それは常にのthread.setContextClassLoader(クラスローダー)の何もしませんし、「アプローチ2」のように見えますシステムクラスローダを使用する(デバッグ中TCLとCCLの変数を比較することによって決定することができる)。
は、それを可能にするためにはすべて新しいスレッドの使用与えられたクラスローダによってロードされたクラス?
解決
あなたはnew Thread("test") { ... }
経由で作成されている匿名クラスは、親インスタンスへの暗黙的な参照を持っています。この匿名クラス内のクラスリテラルは、囲むクラスのクラスローダを使ってロードされます。
このテスト作業を行うためには、あなたが適切なRunnableを実装を引き出し、そして所望のClassLoaderを使って、反射的にそれをロードする必要があります。その後、スレッドに明示的に渡します。ような何かます:
public final class MyRunnable implements Runnable {
public void run() {
System.out.println("running...");
// etc...
}
}
final Class runnableClass = classLoader.loadClass("classloader.MyRunnable");
final Thread thread = new Thread((Runnable) runableClass.newInstance());
thread.setContextClassLoader(classLoader); // this is unnecessary unless you you are using libraries that themselves call .getContextClassLoader()
thread.start();
他のヒント
私はInjectingClassLoaderは、ここで重要なのかもしれないと思います。委任作品をクラスローディング方法を覚えている - あなたの階層に複数のクラスローダがクラスを見つけることができれば、最上位クラスローダがロードそのいずれかになります。 (図21.2 ここを)
InjectingClassLoaderはそのコンストラクタで親を指定していないので、は、それがInjectingClassLoaderの親として、現在のコンテキストクラスローダを設定します抽象クラスローダにコンストラクタにデフォルト設定されます。したがって、親(旧コンテキストクラスローダ)以来InjectingClassLoaderがする機会を得る前に、それは常にクラスをロードし、TestProxyを見つけることができます。