【问题标题】:java.lang.LinkageError on jBoss while running app with log4j custom layout class使用 log4j 自定义布局类运行应用程序时 jBoss 上的 java.lang.LinkageError
【发布时间】:2011-01-29 14:04:13
【问题描述】:

我正在尝试为 Log4J 配置自定义布局类,如 my previous post 中所述。该类使用java.util.regex.Matcher 来识别日志消息中的潜在信用卡号。它可以在单元测试中完美运行,也可以在包含单个 servlet 的最小 Web 应用程序中运行。但是,当我尝试在 JBoss 中使用我们的应用程序部署它时,我收到以下错误:

--- MBEANS THAT ARE THE ROOT CAUSE OF THE PROBLEM ---
ObjectName: jboss.web.deployment:war=MyWebApp-2010_02-SNAPSHOT.war,id=476602902
  State: FAILED
  Reason: java.lang.LinkageError: java/util/regex/Matcher

我什至找不到关于这种形式的错误的任何信息 - 通常 LinkageError 似乎显示“加载程序约束违规”消息,例如在 here 中。

技术细节:我们使用 JBoss 4.2、Java 5、Log4J 1.2.12。我们将我们的应用程序部署在一个 .ear 中,其中包含(以及其他)上面提到的 .war 文件,以及一个单独的 jar 文件中的自定义布局类(我们称之为 Commons)。我们使用位于不同文件夹中的自己的log4j.properties 覆盖jboss-log4j.xml 中的默认设置,该文件夹在启动时添加到类路径中,并通过Sapient's Carbon framework 提供。

更新@skaffman 的回答:

我们有一个单独的 log4j.properties 文件的原因是 Sapient Carbon 传播的方案。这基本上将配置和数据文件从应用程序服务器环境中分离出来,因此它们可以通过 Carbon 的查找功能访问,并且可以存储在应用程序服务器外部的目录中。我们继承了这种设置,但我们讨厌它,因为它不符合 JEE 约定,因此在部署、类路径问题等方面给我们带来了很多麻烦。从长远来看,我们的目标是摆脱它,但这需要时间:-(

尽管单独的 log4j.properties 文件不是最佳实践,但它确实有效。它已经在我们的应用程序中运行了多年,我还可以使它与包含单个 servlet(不使用 Sapient Carbon)的简约 Web 应用程序一起工作。如果将 log4j.properties 放入类路径,Log4J 会在 Web 应用程序启动时正确读取它,并相应地重新配置日志记录。

更新#2: 一个有趣的发现是 Matcher 甚至没有在 MyWebApp 中使用,仅在 Commons 模块(和另一个模块,在单独的 jar 中)中使用。在 Commons 中,之前在一个名为 StringHelper 的类中使用过,MyWebApp 通过其他模块间接使用该类。

我想这排除了由不同类加载器加载两个不同 Matcher 类版本的可能性。所以我唯一剩下的猜测是,当从 jar 和 war 中使用 Matcher 时,它由两个不同的类加载器加载,然后尝试从一个传递到另一个。这由Frank Kieviet's excellent article 解释。但是,我相信这样的设置会导致“违反加载程序约束”而不是这种形式的错误。

更新#3:如果我在 jboss-log4j.xml 中添加 this appender (example 3.8),错误就会消失,服务器运行完美 :-o 这显然与加载 log4j.jar 有关系,因为此设置要求 jar 存在于服务器 lib 目录中。如果我将附加程序类型更改为org.jboss.logging.appender.FileAppender,并将日志级别设置为WARN,它也可以工作,这会导致ucl.log 文件为空。这可能适合作为临时解决方法,但我仍然渴望完全了解这里发生了什么。

此错误消息是什么意思,我该如何正确解决?


结语

经过漫长的等待,我终于从日志进程中删除了 Carbon,并将我们的日志配置迁移到 server/conf/jboss-log4j.xml。这要求我在 server/lib 目录中的单独 jar 中发布我们的自定义日志过滤器类。在此之后,类加载再次工作,没有上面 Update#3 中描述的解决方法:-)

【问题讨论】:

  • 删除了 carbon 标签 - 用于 MacOSX API。
  • @skaffman 很遗憾,存在名称冲突 :-( 感谢您指出这一点。从现在开始,我将“我们的”框架称为“Sapient Carbon”。
  • 一篇很有用的文章:ibm.com/developerworks/views/java/…

标签: java jboss log4j classloader


【解决方案1】:

我的第一反应是在 JBoss 中不可能像那样覆盖 log4j 配置。 JBoss 不允许 log4j 像通常那样定位自己的配置,conf/jboss-log4j.xml 的位置在conf/jboss-service.xml 中指定。

据我所知,给定 JBoss 服务器中的所有 log4j 配置都必须集中到一个文件中,通常是 conf/jboss-log4j.xml

您是否尝试过将log4j.properties 的内容移动到现有的conf/jboss-log4j.xml 文件中?如果这工作正常,那么问题几乎肯定是由您尝试覆盖 log4j 引起的。话虽如此,如果 jboss/log4j 如此脆弱,我会感到惊讶,但也许在某些情况下,它会拒绝这一点。

【讨论】:

    【解决方案2】:

    您要么有两类不同的签名,但在您的环境中具有相同的路径,或者您针对 j.u.r.Matcher 的另一个签名进行编译。由于这是标准 Java API,我认为您应该检查您的源代码和编译目标以及 JBoss 安装的 JVM 运行时版本。

    编辑:

    在排除之后,我敢肯定,管理附加程序并尝试加载使用您的自定义布局的附加程序的类加载器(服务器)看不到自定义布局类实例。所以你有两个选择:

    1. 将您的自定义布局 JAR 与 log4j 一起部署到服务器的 lib 目录。
    2. 将 log4j 与您的应用程序一起部署,并使用您自己的类加载器 (jboss-app.xml) 隔离应用程序:

    <jboss-app> <loader-repository> com.myapplication:loader=MyClassLoader <loader-repository-config>java2ParentDelegation=false</loader-repository-config </loader-repository> </jboss-app>

    我希望,问题会消失。

    【讨论】:

    • 这是关于我已经知道的……不过还是谢谢。
    • 您是否将 log4j 与您的 EAR/WAR 一起部署?当你将你的 layout-JAR 移动到容器的 lib 目录时会发生什么?当要加载布局类时,Matcher 可能是第一个失败点。如果您不使用 EAR/WAR 部署 log4j,则父类加载器的类实例可能无法加载您的布局,因为加载器看不到 JAR。也许尝试将 log4j 与您的应用程序一起部署并查看 jboss-app.xml 上的“Java2ParentDelegation”。
    • Log4J 未部署在 EAR 或 WAR 中。到目前为止,它存在于服务器 lib 目录中,但我删除了它,这并没有改变任何东西。怀疑是自定义布局类加载了,否则没有LinkageError。
    • 由于 Sapient Carbon,我无法隔离 EAR 类加载器 :-((( 我在没有隔离的情况下尝试了您上面的两个建议,但 LinkageError 占上风。请注意,尽管我找到了一种解决方法,因为我在上面帖子的更新#3 中描述。这也表明找到自定义布局类本身不是问题。
    • 是的,log4j 正在做一些讨厌的类加载。这也是 Log4j 创始人开始 Logback 的原因之一。 ;)
    猜你喜欢
    • 2021-01-15
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多