我的申请有问题。为了恢复这个问题,我不得不将应用程序从 jboss 4 迁移到 jboss 5。
在 war 部署期间,我遇到了这个错误:
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
经过多次搜索,我发现这个错误就在这里,因为我在不同的包中有好几次同一个类。一次在依赖包中(来 self 的 pom.xml),一次由 jboss 提供。
因此,为了解决这个问题,我为我的依赖项“提供”了一个范围。
但我不明白为什么这个解决方案有效。我认为在一个应用程序中多次使用同一个类是可行的。我知道这不是一件好事,但对于 jboss 4,它很管用。
有人可以解释为什么它适用于 jboss 4 而不适用于 jboss 5。
感谢您的解释:)
最佳答案
您看到的是应用服务器在单独的类加载器中加载 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
编辑:
只是两个地址的两个评论 -
jtahlborn 指出的类加载行为绝对不同。在正常的应用程序中,像 QName 这样的系统类将始终在引导类加载器中查找。在您的错误中,它看起来好像正在 org/jboss/classloader/spi/base/BaseClassLoader 中加载 javax/xml/datatype/DatatypeConstants。让我们假设这就是 EAR 类加载器(或 WAR)。快速谷歌显示它是 xml-apis 家族的一部分,也可能是 jaxp-api。
因此您的代码(或位于 EAR 的类加载器中的另一个库代码)中的某处需要 DatatypeConstants - 这会强制在 EAR 的类加载器中查找类。尽管 QName 对象的创建从引导类加载器(而不是 EAR)加载了类。如果 QName 类已经被系统初始化,就会发生这种情况,它可能已经初始化了。
正如您想象的那样,这是不可能发生的。它实际上看起来像你有 parent 最后。因为当从 JBoss 类加载机制加载一个类时,如果启用了父级优先,则初始 DatatypeConstants 将返回父级( Bootstrap )的 DatatypeConstants 而不是子级。因此,正如 jtahlborn 所指出的,您可能希望忽略此处的子类加载器。
就解决方案而言,除非您出于特定原因需要依赖项(例如稍微更新的版本比当前版本更好),否则我会委托(delegate)给 jboss 的实现。如果不是这种情况,您可以查看 jboss 配置中的 class-loading java2ClassLoadingCompliance
元素。
关于java - Jboss 5、类加载器和多个类实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5638191/