【问题标题】:Java Thread context classloader - how does it work?Java 线程上下文类加载器 - 它是如何工作的?
【发布时间】:2014-04-20 05:46:42
【问题描述】:

我在互联网上找到了以下 OSGi 的加载器结构。

引导类加载器(来自 jre/lib/rt.jar 的 Java 标准库 等)
^
扩展类加载器
^
系统 类加载器(即 $CLASSPATH 上的东西,OSGi 核心代码)
^ (** 限制从父类加载器访问类型
common OSGi 类加载器:
--|-- 用于 bundle1 的 OSGi 类加载器->(导入包的映射->类加载器)
--|-- 用于 bundle2 的 OSGi 类加载器->(导入包的映射->类加载器)
--|-- bundle3 的 OSGi 类加载器 -> (imported-package->classloader 的映射)

Here 上面写着

在执行线程上设置的上下文类加载器。默认情况下是 始终设置为 System classloader 或从新的线程 线程实例已创建。

从上面的结构中我们看到系统加载器(=上下文加载器)具有更高的位置,据我所知,父类加载器从不询问它的子类。

所以我的问题请解释当前线程如何与当前包中的类一起工作?

【问题讨论】:

  • 在 OSGI Thread.currentThread().getContextClassLoader() 返回一个特殊的 OSGI 捆绑类加载器。在 Equinox 中,它是 org.eclipse.osgi.framework.internal.core.BundleClassLoader。这个类加载器由 OSGI 容器设置,只知道MANIFEST.MFBundle-ClassPath 定义的导入包和类(默认是. => 包本身)
  • @drkunibar 我不了解 Equinox,但在 felix 中,Thread.currentThread().getContextClassLoader() 返回 sun.misc.Launcher$AppClassLoader@2f0f94a0,this.getClass().getClassLoader 返回 org .apache.felix.framework.BundleWiringImpl@51dd475f。您的解释似乎有问题。
  • 您可以在 OSGi 核心规范中找到有关 OSGi 中类加载器的所有信息。 servlet 容器经常使用线程上下文类加载器。调用Web应用程序时,将Web应用程序的类加载器设置为线程上下文类加载器。技术开发人员通常使用线程上下文类加载器来确保他们看到 webapp 中可用的所有类。在 OSGi 中,你永远不应该依赖线程上下文类加载器,也不应该使用依赖于线程上下文类加载器的技术。
  • @P82 我对felix一无所知,但是Thread.currentThread().getContextClassLoader()返回的类加载器可以和this.getClass().getClassLoader不同,因为第一个可以改(第二个不能改)。如果您考虑在 OSGI 中加载类,您应该阅读此博客:blog.osgi.org/2011/05/what-you-should-know-about-class.html
  • 上面cmets中有些信息是假的。在 OSGi 中,线程上下文类加载器只是 undefined。你不能断言或期望它是特定的东西,事实上它可能是空的。

标签: java multithreading jakarta-ee osgi


【解决方案1】:

在 OSGi 中,线程上下文类加载器 (TCCL) 是未定义的。你不能期望或断言它会是什么特别的东西。其实很多时候都是null

TCCL 是在 Java 1.2 中添加的一个 hack,用于支持 J2EE。具体来说,它需要支持实体 Bean 之类的东西;在现代世界中,它用于支持 JPA、JAXB、Hibernate 等技术。

父委托的问题在于,虽然底部的应用程序类可以看到父类加载器中的所有类,但不幸的是,父类加载器加载的类对应用程序具有可见性类。实际上,这意味着您的应用程序代码可以加载(比如说)构成 Hibernate 的类,但 Hibernate 将无法加载您的域类,因为它们在层次结构中位于它之下。

因此,发明了 TCCL。在 J2EE 应用程序服务器中,TCCL 被创建为线程局部变量,并且它具有所有应用程序类的可见性。 Hibernate/JPA/JAXB 等可以查阅 TCCL 以查找应用程序类。这在 J2EE 中很容易做到,因为应用服务器控制着所有的入口点:它控制着 Web 服务器,它控制着 RMI 端点,而且作为应用程序开发人员,您不能创建自己的线程。

不过,OSGi 的编程环境受到的限制要小得多。任何捆绑软件都可以创建自己的网络端点,启动自己的线程,或者几乎可以做任何事情。因此,OSGi 没有机会干预和强加具有应用程序类可见性的 TCCL。此外,“应用程序”的概念本身是模糊的,因为我们有一个称为模块化的简洁的东西。一个应用程序由多个包组成……但是如何定义哪些包可以为 TCCL 提供类?

因此,OSGi 基本上在这个问题上进行了抨击。 TCCL 是未定义的,所以你永远不应该依赖它。幸运的是,大多数尝试使用的库仅将其作为他们尝试从中加载类的一系列位置之一。

【讨论】:

  • 感谢您的宝贵时间。这个问题来自另一个问题——解决转换问题是从 EJB 返回的 OSGi。谷歌搜索后,我找到了三个解决方案:使用 TCCL、反射和 Transloader。我在这里描述的这些解决方案stackoverflow.com/questions/23168885。我在这里描述了 TCCL 的问题stackoverflow.com/questions/23174582。所以要么我不应该使用 TCCL - 我该如何解决铸造问题或如何使用 TCCL 来解决它?四天了,我不能从同一个地方搬家。你能至少给我一个提示吗?
  • 我将就这些问题中最相关的问题发布答案。
  • 同时,接受或至少支持这个答案将不胜感激......假设您发现它有用或信息丰富;-)
  • 我已经在这里发布了所有信息。 stackoverflow.com/questions/23174582 我能做的我都做了。解决方案在我的能力之外。
  • 正如人们所说,该类同时被两个类加载器加载。其中一个是 OSGi 捆绑类加载器,另一个是由于 EJB 的参与而与 Java RMI 相关的东西。除此之外,我无能为力,因为我已经很多年没有使用 RMI 或 EJB 了(并且摆脱了它们!)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-18
  • 1970-01-01
  • 2015-08-30
  • 2020-12-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多