如何使用自定义ClassLoader?

roe*_*erj 29 java classloader

大家好,感谢您的关注!我有一个既容易又明显的问题,但我被卡住了.

我想通过自定义ClassLoader提供动态创建的Java类,供第三方库使用.

现在我的问题是:当我不自己直接加载这些类时,如何设置我的自定义ClassLoader来加载这些类?

我想当我使用我的ClassLoader加载某个类时,它就变成了这个类的ClassLoader,并且从该类加载的所有类都将通过我的ClassLoader引导.

我按照这个官方教程创建了一个自定义的ClassLoader:http://java.sun.com/developer/onlineTraining/Security/Fundamentals/magercises/ClassLoader/help.html.

public class DynamicClassloader extends ClassLoader {

    private Map<String, Class<?>> classesMap = new HashMap<String, Class<?>>();

    public DynamicClassloader(ClassLoader parent) {
        // Also tried super(parent);
        super(sun.misc.Launcher.getLauncher().getClassLoader());
    }

    // Adding dynamically created classes
    public void defineClass(String name, Class<?> clazz) {
        classesMap.put(name, clazz);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // load from parent
        Class<?> result = findLoadedClass(name);
        if (result != null) {
            return result;
        }
        try {
            result = findSystemClass(name);
        } catch (Exception e) {
            // Ignore these
        }
        if (result != null) {
            return result;
        }
        result = classesMap.get(name);
        if (result == null) {
            throw new ClassNotFoundException(name);
        }
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想在代码中的其他地方使用它:

ClassLoader thisClassLoader = this.getClass().getClassLoader();
((DynamicClassloader) thisClassLoader).defineClass(className, dynClass);
Run Code Online (Sandbox Code Playgroud)

现在我的问题是当我调用findSystemClass(name)第三方库类时,父类ClassLoader找到这个类(因为它在类路径上)并成为它的ClassLoader.由于父类ClassLoader不知道我的自定义ClassLoader,因此它实际上已经停止使用,this.getClass().getClassLoader()无法转换为DynamicClassLoader.

另一种方法是通过JVM参数将我的ClassLoader设置为系统ClassLoader -Djava.system.class.loader=my.DynamicClassloader.但是这给了我一个StackOverflowError:

    ...
at de.unisaarland.cs.st.DynamicClassloader.findClass(DynamicClassloader.java:39)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.ClassLoader.findSystemClass(ClassLoader.java:916)
at de.unisaarland.cs.st.DynamicClassloader.findClass(DynamicClassloader.java:39)
    ...
Run Code Online (Sandbox Code Playgroud)

这一定非常容易,但我现在已经没有想法...非常感谢任何帮助!

pgr*_*ras 22

我不确定我是否理解这个问题,你有第三方库,你希望它使用你的类加载器来加载类.

如果你很幸运,第三方lib使用你可以设置的线程上下文类加载器Thread.currentThread().setContextClassLoader(myClassLoader),在同一个线程中你可以用Thread.currentThread().getContextClassLoader()... 访问这个类加载器.

另一点,但不确定它在您的上下文中是否重要,是您还可以编写一个父级最后一个类加载器,它将在委托给父级之前尝试加载该类(而不是先尝试委托)

在您的评论后编辑:

如果您的库不依赖于线程上下文类加载器,那么parent_last类加载器会有所不同,那么您必须使用父级最后一个类加载器加载库,从而将类加载器设置为库的类加载器而不是其父加载器(父类)你的类加载器)...

您也可以创建一个具有父亲优先行为的类加载器,但是对于您的第三方库...

关于类加载器的良好链接......