gpt4 book ai didi

java - 线程的上下文类加载器和普通类加载器的区别

转载 作者:bug小助手 更新时间:2023-10-28 10:41:39 24 4
gpt4 key购买 nike

线程的上下文类加载器和普通的类加载器有什么区别?

即如果Thread.currentThread().getContextClassLoader()getClass().getClassLoader()返回不同的类加载器对象,会使用哪一个呢?

最佳答案

这并没有回答原始问题,但由于该问题对于任何 ContextClassLoader 查询的排名和链接都很高,我认为回答上下文类加载器何时应该是相关问题很重要用过的。简短的回答:永远不要使用上下文类加载器!但是,当您必须调用缺少 ClassLoader 参数的方法时,请将其设置为 getClass().getClassLoader()

当一个类的代码要求加载另一个类时,要使用的正确类加载器是与调用者类相同的类加载器(即,getClass().getClassLoader())。 99.9% 的时间都是这样,因为 this is what the JVM does itself第一次构造新类的实例、调用静态方法或访问静态字段时。

当您想使用反射创建类时(例如反序列化或加载可配置的命名类时),执行反射的库应始终询问应用程序使用哪个类加载器,通过从应用程序接收 ClassLoader 作为参数。应用程序(知道所有需要构建的类)应该传递它getClass().getClassLoader()

获取类加载器的任何其他方式都是不正确的。如果图书馆使用了诸如 Thread.getContextClassLoader() 之类的技巧, sun.misc.VM.latestUserDefinedLoader() , 或 sun.reflect.Reflection.getCallerClass()这是由 API 缺陷引起的错误。基本上,Thread.getContextClassLoader() 的存在只是因为设计 ObjectInputStream API 的人忘记接受 ClassLoader 作为参数,而这个错误一直困扰着Java 社区至今。

也就是说,许多 JDK 类使用一些技巧之一来猜测要使用的类加载器。有些使用 ContextClassLoader(当您在共享线程池上运行不同的应用程序时失败,或者当您离开 ContextClassLoader null 时),有些使用堆栈(当类的直接调用者本身就是一个库),一些使用系统类加载器(这很好,只要它被记录为仅使用 CLASSPATH 中的类)或引导类加载器,还有一些使用上述技术的不可预测的组合(这只会使事情变得更加困惑)。这导致许多人哭泣和咬牙切齿。

在使用这样的 API 时,首先,尝试找到接受类加载器作为参数的方法的重载。如果没有合理的方法,请尝试在 API 调用之前设置 ContextClassLoader(并在之后重置它):

ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
// call some API that uses reflection without taking ClassLoader param
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}

关于java - 线程的上下文类加载器和普通类加载器的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1771679/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com