Java 如何使用自定义类加载器?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4095976/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 11:35:33  来源:igfitidea点击:

How to put custom ClassLoader to use?

javaclassloader

提问by roesslerj

Hello all and thanks for the attention! I have a problem that must both be easy and obvious, yet I am stuck.

大家好,感谢关注!我有一个既简单又明显的问题,但我被卡住了。

I want to deliver dynamically created Java classes to be used by a 3rd party library via a custom ClassLoader.

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

Now my problem is: How do I set my custom ClassLoader to be used to load this classes when I do not load them directly myself?

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

I thought when I used my ClassLoader to load a certain class, it became this class's ClassLoader, and all classes loaded from that class would be channeled through my ClassLoader.

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

I created a custom ClassLoader, following this official tutorial: http://java.sun.com/developer/onlineTraining/Security/Fundamentals/magercises/ClassLoader/help.html.

我按照这个官方教程创建了一个自定义类加载器: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;
    }
}

I wanted to use this somewhere else in the code like that:

我想在代码中的其他地方使用它,如下所示:

ClassLoader thisClassLoader = this.getClass().getClassLoader();
((DynamicClassloader) thisClassLoader).defineClass(className, dynClass);

Now my problem is that when I call findSystemClass(name)of the 3rd party library class, the parent ClassLoader finds this class (because it is on the classpath) and becomes its ClassLoader. And since the parent ClassLoader doesn't know about my custom ClassLoader, it is effectively been put out of use and this.getClass().getClassLoader()cannot be cast to DynamicClassLoader.

现在我的问题是,当我调用findSystemClass(name)3rd 方库类时,父类加载器找到了这个类(因为它在类路径上)并成为它的类加载器。并且由于父类加载器不知道我的自定义类加载器,因此它实际上已不再使用并且this.getClass().getClassLoader()无法转换为 DynamicClassLoader。

Another approach would be to set my ClassLoader to be the system ClassLoader via JVM argument -Djava.system.class.loader=my.DynamicClassloader. But that gives me a StackOverflowError:

另一种方法是通过 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)
    ...

This must be really easy to do, yet I am now out of ideas... any help is greatly appreciated!

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

采纳答案by pgras

Not sure I understand the question, you have a 3rd party lib and you want it to use your classloader to load classes.

不确定我是否理解这个问题,您有一个 3rd 方库并且您希望它使用您的类加载器来加载类。

If you're lucky the third party lib uses the threads context classloader which you can set using Thread.currentThread().setContextClassLoader(myClassLoader), in the same thread you can access this classloader with Thread.currentThread().getContextClassLoader()...

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

Another point, but not sure it is important in your context, is that you can also write a parent-last classloader that will try to load the class before delegating to its parent (instead of trying to delegate first)

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

Edited after your comment:

在您的评论后编辑:

parent_last classloader will make a difference if your library doesn't rely on the thread context classloader, then you have to load the library with your parent-last classloader thus setting your classloader as the classloader for the library instead of its parent loader (the parent of your classloader)...

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

You may also make a classloader with a parent-first behavior but for your 3rd party library...

您也可以制作一个具有父级优先行为的类加载器,但对于您的第 3 方库...

And a good link about classloaders...

还有一个关于类加载器的好链接......