-
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器(classloader)的无助和“办法2”始终使用系统类加载器(可通过比较TCL和CCl变量在调试时进行测定)。
时,有可能使全部按新的线程使用给定的类加载器加载的类?
解决方案
在经由new Thread("test") { ... }
创建匿名类具有包围实例的隐式引用。这个匿名类内类文字将使用封闭类的类加载器加载。
为了使这种测试工作,你应该拔出适当的可运行执行,并反射地使用所需的类加载器加载它;然后传递明确的线索。是这样的:
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的父。因此,由于母公司(旧上下文的classloader)可以找到TestProxy,它总是加载InjectingClassLoader前级都有机会。
不隶属于 StackOverflow