本文介绍了更改类加载器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在运行时切换类加载器:

I'm trying to switch the class loader at runtime:

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 的类,它应该先加载类的修改版本,然后再询问它们的父类。)

(InjectingClassLoader is a class extending the org.apache.bcel.util.ClassLoader which should load the modified versions of classes before asking it's parent for them)

I我想使方法1和方法2的结果完全相同,但它看起来像 thread.setContextClassLoader(classLoader)什么都不做,方法2总是使用系统类加载器(可以通过在调试时比较tcl和ccl变量来确定)。

I'd like to make the result of "approach 1" and "approach 2" exactly same, but it looks like thread.setContextClassLoader(classLoader) does nothing and the "approach 2" always uses the system classloader (can be determined by comparing tcl and ccl variables while debugging).

是否可以使用给定类加载器的新线程加载所有类?

Is it possible to make all classes loaded by new thread use given classloader?

推荐答案

您通过新线程(测试)创建的匿名类{... } 具有对封闭实例的隐式引用。此匿名类中的类文字将使用封闭类的ClassLoader加载。

The anonymous class you are creating via new Thread("test") { ... } has an implicit reference to the enclosing instance. Class literals within this anonymous class will be loaded using the enclosing class's ClassLoader.

为了使此测试工作,您应该提取一个正确的Runnable实现,并加载它反过来使用所需的ClassLoader;然后将其明确传递给线程。类似于:

In order to make this test work, you should pull out a proper Runnable implementation, and load it reflectively using the desired ClassLoader; then pass that explicitly to the thread. Something like:

    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();

这篇关于更改类加载器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-12 07:57