【问题标题】:Jboss 5, classloader and multiple class instancesJboss 5、类加载器和多个类实例
【发布时间】:2014-03-16 15:00:09
【问题描述】:

我的申请有问题。为了解决这个问题,我不得不将应用程序从 jboss 4 迁移到 jboss 5。

在战争部署期间,我遇到了这个错误:

java.lang.LinkageError: loader constraint violation: when resolving field "DATETIME"
the class loader (instance of org/jboss/classloader/spi/base/BaseClassLoader) of the referring class,
javax/xml/datatype/DatatypeConstants, and the class loader (instance of <bootloader>)
for the field's resolved type, javax/xml/namespace/QName,
have different Class objects for that type

经过多次搜索,我发现这个错误就在这里,因为我在不同的包中有多次相同的类。一次在依赖包中(来自我的 pom.xml),一次由 jboss 提供。

所以,为了解决这个问题,我为我的依赖项“提供”了一个范围。

但我不明白为什么这个解决方案有效。我认为在应用程序中多次使用同一类是可行的。我知道这不是一件好事,但有了 jboss 4,它就可以了。

有人可以解释一下为什么它适用于 jboss 4 而不适用于 jboss 5。

感谢您的解释:)

【问题讨论】:

  • 重复的类是什么?它重复到哪些包中?
  • 你在哪里设置提供,谢谢

标签: java jboss dependencies


【解决方案1】:

您看到的是应用服务器在不同的类加载器中加载 JBoss 的库和 EAR 库的效果

您可以认为 EAR 的类加载器层次结构类似于(但不一定):

Bootstrap 类加载器 -> 系统类加载器 -> JBoss 系统类加载器 -> Ear 类加载器 -> War 类加载器。

war 类加载器的父类是 ear 类加载器等等。

现在,如果 Bootstrap ClasssLoader 加载了一个 jar A 并且 ear 也使用 jar A 部署,Bootstrap Class Lodaer 和 Ear Class Loader 将在不同的类加载器中创建两次相同的类。

我会假设(不是 100% 肯定)JBoss 4 没有与 javax/xml/namespace/QName 捆绑在一起。如果这是真的,那么 JBoss 5 很可能是 Java 的不同升级版本(4 -> 5 或 5 -> 6)。因此(使用新的 JBoss 5),当您尝试将 javax/xml/namespace/QName 传递到您的某个类中时,它会期望该类来自耳朵。但是,由于类加载器首选项(父级优先等),您从 Bootstrap 类加载器中为其提供 QName 类。

由于类类型相等但类实例不相等,你会得到一个 LinkageError

编辑:

只有两个地址两个 cmets -

jtahlborn 指出的类加载行为肯定是不同的。在普通应用程序中,系统类(如 QName)将始终在引导类加载器中查找。在您的错误中,似乎 javax/xml/datatype/DatatypeConstants 正在加载到 org/jboss/classloader/spi/base/BaseClassLoader。让我们假设那是 EAR 类加载器(或 WAR)。一个快速的谷歌显示它是 xml-apis 家族的一部分,可能是 jaxp-api。

因此,在您的代码(或位于 EAR 的类加载器中的其他库代码)中的某处需要 DatatypeConstants - 这会强制在 EAR 的类加载器中查找类。通过从引导类加载器(而不是 EAR)加载类来创建 QName 对象。如果系统已经初始化了 QName 类,就会发生这种情况。

您可以想象,这不会发生。它实际上看起来像你有父母最后。因为当从 JBoss 类加载机制中加载一个类时,如果启用了 parent-first,则初始 DatatypeConstants 将返回父级(引导)DatatypeConstants 而不是子级。因此,正如 jtahlborn 所指出的,您希望这里的子类加载器被忽略。

就解决方案而言,除非您出于特定原因需要依赖项(例如稍新的版本比当前版本更好),否则我将委托给 jboss 的实现。如果不是这样,您可以查看 jboss 配置所具有的class-loading java2ClassLoadingCompliance 元素。

【讨论】:

  • 我认为这很接近,但并不完全正确。通常,war 类加载器设置为更喜欢从子级加载。否则,您将永远不会看到冲突,因为战争中类的版本将被忽略。你说得对,最可能的问题是java版本的不同(我怀疑jboss包括jaxb类)。
  • 通过将 websphere 和 weblogic 升级到较新版本(包括较新版本的 Java),我学到的是 java 运行时包含自己的 javax/xml/namespace/QName 和相关库。这就是我认为OP的问题。是的,你是正确的默认配置通常是假设 parent-last。
  • 您应该澄清在这种情况下类加载行为是不同的,因为这会使 OP 感到困惑。在“普通”Java 应用程序中,子类加载器中包含的重复类将被忽略。
  • 如何在 parent-last 设置配置?
  • 关于您的编辑。事实上,我已经尝试过类加载器 java2ClassLoadingCompliance,但是有了这个,我遇到了一个关于记录器配置的新错误。最后,最好为我的应用程序使用 jboss 默认的comportment。非常感谢您非常完整的解释:)
【解决方案2】:

-verbose:class 在 VM args 中将给出类的加载方式。 如果有重复,您可以删除冲突的 jar/jars。

【讨论】:

    【解决方案3】:

    感谢您的解释 - 它非常有帮助。

    我了解到这个问题与在 5.0.0 版本中修复的 JBoss 错误有关。但是即使我运行的是旧版本的 JBoss,我仍然会收到此错误。 无论如何,我进行了广泛的研究并运行了几次 maven 依赖树,以查看重复定义的来源。我终于能够通过向我的主 pom 添加两个依赖项(范围设置为提供)来解决此错误:
    (sun.jaxb-impl 2.1 , javax.jaxb-api 2.2 ) 我希望这些信息对某人有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多