【问题标题】:How to change default class loader in Java?如何更改 Java 中的默认类加载器?
【发布时间】:2011-09-16 00:21:17
【问题描述】:

假设我有三个类,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ŭlo Ebermann 在下面的回答,我认为问题是我正在调用父类加载器 (URLClassLoader) 来加载我不需要触摸的类,并且那些加载的类将其设置为上下文类加载器,因此从它导入的类使用我的自定义加载器的父类加载器。 (令人困惑,抱歉)现在我可以通过手动读取每个类来让它工作,但是这似乎是多余的,因为我直接复制了 URLClassLoader 的代码。有没有办法告诉父类加载器查找和定义类,但将类的上下文类加载器设置为您的自定义类加载器?

【问题讨论】:

  • 加载的类没有将父类设置为它们的“上下文”类加载器。父类是加载类的物理“文件”加载器,这就是为什么这些类使用父类来进一步加载它们需要的依赖项。请参阅stackoverflow.com/a/25489403/632951 了解更多信息。

标签: java class classloader


【解决方案1】:

如果你的类加载器实现正确,它会首先询问它的父类加载器是否应该加载任何类。

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

您的类加载器定义的所有类也将在您的类加载器上搜索它们所需的类。如果他们不这样做,你的 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 是另外一回事 - 它是特定于线程的,并且仅由明确想要使用它的类使用,而不是由解决它们自己的直接依赖关系的类使用。)

【讨论】:

  • 你是说因为我在我的类加载器上调用了getParent.loadClass(name),它导入的类使用我的类加载器的父类等等?
  • 如果是这样,有没有办法让父类加载类,但将上下文类加载器(这是正确的术语?)设置为我的自定义类?我不想编写文件阅读器并完成所有加载工作。
  • 你可以继承 URLClassloader 并覆盖 loadClass() 那里。但是为什么你需要一个自定义的类加载器呢?
  • 我正在修改特定包的某些类的字节码,然后再加载它们并将其余部分与父包一起加载。
  • But why do you need a custom class loader at all? 一百万零五个原因。
猜你喜欢
  • 1970-01-01
  • 2020-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-06
  • 2023-03-17
  • 1970-01-01
相关资源
最近更新 更多