Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 螺纹与x27之间的差异;s上下文类加载器和普通类加载器_Java_Multithreading_Jvm_Classloader - Fatal编程技术网

Java 螺纹与x27之间的差异;s上下文类加载器和普通类加载器

Java 螺纹与x27之间的差异;s上下文类加载器和普通类加载器,java,multithreading,jvm,classloader,Java,Multithreading,Jvm,Classloader,线程的上下文类加载器和普通类加载器之间有什么区别 也就是说,如果Thread.currentThread().getContextClassLoader()和getClass().getClassLoader()返回不同的类加载器对象,将使用哪一个对象?每个类将使用自己的类加载器加载其他类。因此,如果ClassA.class引用了ClassB.class,那么ClassB需要位于ClassA的类加载器或其父类的类路径上 线程上下文类加载器是当前线程的当前类加载器。可以从classloader中的

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


也就是说,如果
Thread.currentThread().getContextClassLoader()
getClass().getClassLoader()
返回不同的类加载器对象,将使用哪一个对象?

每个类将使用自己的类加载器加载其他类。因此,如果
ClassA.class
引用了
ClassB.class
,那么
ClassB
需要位于
ClassA
的类加载器或其父类的类路径上


线程上下文类加载器是当前线程的当前类加载器。可以从
classloader
中的类创建对象,然后将其传递给
ClassLoaderD
所拥有的线程。在这种情况下,如果对象希望加载其自己的类加载器上不可用的资源,则需要直接使用
Thread.currentThread().getContextClassLoader()

infoworld.com上有一篇文章解释了这一区别 =>

(一)

线程上下文类加载器提供 在教室的后门 授权计划

以JNDI为例:它的胆量是 由中的引导类实现 jar(从J2SE 1.3开始),但是 这些核心JNDI类可以加载JNDI 由独立供应商实施的供应商 供应商和可能部署在 应用程序的类路径。这 这个场景需要一个家长 类装入器(中的原始类装入器) 在这种情况下)加载对用户可见的类 它的一个子类装入器( 例如,系统一)。正常J2SE 授权不起作用,而 解决方法是制作核心JNDI 类使用线程上下文加载器, 从而有效地“隧道”通过 中的类加载器层次结构 与正确方向相反的方向 代表团

(2) 来自同一来源:

这种困惑可能会一直持续下去 Java已经有一段时间了。以任何J2SEAPI为例 动态加载任何资源 然后试着猜猜是哪种装载 它使用的策略。以下是一个样本:

  • JNDI使用上下文类加载器
  • Class.getResource()和Class.forName()使用当前的类加载器
  • JAXP使用上下文类加载器(从J2SE1.4开始)
  • ResourceBundle使用调用方的当前类加载器
  • 通过java.protocol.handler.pkgs系统属性指定的URL协议处理程序仅在引导程序和系统类加载器中查找
  • 默认情况下,Java序列化API使用调用方的当前类加载器

除了@David Roussel answer,类可以由多个类加载器加载

让我们了解它是如何工作的

摘自javin paul在爪哇的博客重温:

ClassLoader
遵循三个原则

授权原则 在需要时,用Java加载一个类。假设您有一个名为Abc.class的特定于应用程序的类,加载该类的第一个请求将到达application ClassLoader,application ClassLoader将委托给其父扩展ClassLoader,父扩展ClassLoader将进一步委托给Primordial或Bootstrap class loader

  • 引导类加载器负责从rt.jar加载标准JDK类文件,它是Java中所有类加载器的父类。引导类装入器没有任何父类

  • 扩展类加载器将类加载请求委托给其父级引导,如果不成功,则从jre/lib/ext目录或java.ext.dirs系统属性指向的任何其他目录加载类

  • 系统或应用程序类加载器,它负责从CLASSPATH环境变量、-CLASSPATH或-cp命令行选项、JAR内清单文件的CLASSPATH属性加载特定于应用程序的类

  • 应用程序类加载器是扩展类加载器的子类,它由
    sun.misc.Launcher$AppClassLoader
    类实现

注意:除了Bootstrap类加载器(主要用C语言实现)之外,所有Java类加载器都是使用
Java.lang.ClassLoader
实现的

可见度原理 根据可见性原则,子类加载器可以看到父类加载器加载的类,反之亦然

唯一性原则 根据这个原则,父类装入的类不应该再由子类装入器装入


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

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

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

获取类加载器的任何其他方法都是不正确的。如果一个库使用了黑客,比如,或者它是由API中的缺陷引起的错误。基本上,
Thread.getContextClassLoader()
的存在只是因为设计

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);
}