更改类加载器
问题内容:
我试图在运行时切换类加载器:
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变量,同时进行调试)。
是否有可能使新线程加载的 所有 类 都 使用给定的classloader?
问题答案:
您通过其创建的匿名类new Thread("test") { ... }
具有对封闭实例的隐式引用。将使用封闭类的ClassLoader加载此匿名类中的类文字。
为了使该测试有效,您应该提取一个适当的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();