如何在Java中更改默认类加载器?

时间:2011-06-16 01:48:15

标签: java class classloader

假设我有三个类,example.ClassA,example.ClassB和example.ClassLoader。 ClassA打印出HelloWorld,ClassB导入example.ClassA并调用其main()方法。如果我这样做:

  

java -cp Example.jar -Djava.system.class.loader = example.ClassLoader example.ClassA

它工作并使用我的类加载器。但是,如果我这样做:

  

java -cp Example.jar -Djava.system.class.loader = example.ClassLoader example.ClassB

ClassB使用我的类加载器,但ClassA(由ClassB导入)使用默认的类加载器加载。

有没有办法强制Java总是使用我的类加载器(除非明确指定了另一个类加载器)?

编辑:感谢PaŭloEbermann在下面给出的答案,我认为问题在于我正在调用父类加载器(URLClassLoader)来加载我不需要触摸的类,并且那些加载的类设置了它,因为它是上下文类加载器,因此从它导入的类使用我的自定义加载器的父类加载器。 (令人困惑,抱歉)现在我可以通过手动读取每个类来使它工作,但是它似乎是多余的,因为我直接复制了URLClassLoader的代码。有没有办法告诉父类加载器查找和定义类,但是将Class的上下文类加载器设置为自定义类?

1 个答案:

答案 0 :(得分:6)

如果您的类加载器是正确实现的,它将首先向其父类加载器询问应该加载的任何类。

加载器的父类加载器可能是通常的应用程序类加载器。这意味着您的类加载器加载的每个类将首先在应用程序类加载器上进行搜索,并且只有在未找到时才会在您的类加载器上进行搜索。

由类加载器定义的所有类也将在类加载器上搜索所需的类。如果他们不这样做,你的ClassA就不会被装载者真正加载。

如果这没有帮助,您需要显示一些有关如何获得结果的代码。


关于该怎么做的想法:

class ModifyingClassLoader extends URLClassLoader {

    // TODO: add constructors

    private boolean needsModifying(String name) {
        // TODO
    }

    private byte[] modifyClass(InputStream original) throws IOException {
        // TODO
    }

    public Class<?> findClass(String name) throws {
        if(needsModifying(name)) {
            try {
                InputStream classData = getResourceAsStream(name.replace('.', '/') + ".class");
                if(classData == null) {
                    throw new ClassNotFoundException("class " + name + " is not findable");
                }
                byte[] array = modifyClass(classData);
                return defineClass(name, array, 0, array.length);
            }
            catch(IOException io) {
                throw new ClassNotFoundException(io);
            }
        }
        else {
            return super.findClass(name);
        }
    }
}

问题:

  

有没有办法告诉父类加载器查找和定义类,   但是将Class的上下文类加载器设置为自定义加载器?

没有。类的ClassLoader始终是调用defineClass方法来创建类的类。 (context class loader是其他东西 - 它是特定于线程的,仅由明确想要使用它的类使用,而不是由解析它们自己的直接依赖项的类使用。)