如何使用自定义ClassLoader? [英] How to put custom ClassLoader to use?

查看:261
本文介绍了如何使用自定义ClassLoader?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

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

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

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加载某个类时,它变成了这个类的ClassLoader,并且从该类加载的所有类都将通过我的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: http://java.sun.com/developer/onlineTraining/Security/Fundamentals/magercises/ClassLoader/help.html

I created a custom ClassLoader, following this official tutorial: 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);

现在我的问题是当我打电话给 findSystemClass(name),父类ClassLoader找到这个类(因为它在类路径上)并成为它的ClassLoader。由于父ClassLoader不知道我的自定义ClassLoader,它实际上已经不再使用了,并且 this.getClass()。getClassLoader()无法强制转换为DynamicClassLoader 。

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.

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

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:

    ...
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!

推荐答案

我不明白这个问题,你有第三方库,你希望它使用你的类加载器加载类。

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

如果你很幸运,第三方lib使用线程上下文类加载器,您可以使用 Thread.currentThread()。setContextClassLoader(myClassLoader),在同一个线程中,您可以使用<$ c访问此类加载器$ c> Thread.currentThread()。getContextClassLoader() ...

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

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

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)

已编辑在您的评论之后:

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

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)...

你也可以制作一个classloader具有父亲优先行为,但适用于您的第三方库...

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

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

这篇关于如何使用自定义ClassLoader?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆