gwt + jetty + spring + log4j错误:" DOMConfigurator对象不能分配给配置器"

时间:2014-06-08 09:04:07

标签: spring gwt logging log4j jetty

在网络上的几个来源中提到了这个问题,但我无法通过那里提供的解决方案来解决它。

问题: 发出 mvn gwt:run 时,log4j会抛出以下错误:

[ERROR] log4j:ERROR A "org.apache.log4j.xml.DOMConfigurator" object is not assignable to a "org.apache.log4j.spi.Configurator" variable.
[ERROR] log4j:ERROR The class "org.apache.log4j.spi.Configurator" was loaded by
[ERROR] log4j:ERROR [sun.misc.Launcher$AppClassLoader@23137792] whereas object of type
[ERROR] log4j:ERROR "org.apache.log4j.xml.DOMConfigurator" was loaded by [WebAppClassLoader=Demo@3d1665ac].
[ERROR] log4j:ERROR Could not instantiate configurator [org.apache.log4j.xml.DOMConfigurator].

我的项目描述: 我使用gwt提供的默认jetty服务器并在爆炸战争中运行它。

<gwt.version>2.6.1</gwt.version>
<spring.version>3.2.6.RELEASE</spring.version>
<log4j.version>1.2.17</log4j.version>
<slf4j.version>1.7.5</slf4j.version>

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>${log4j.version}</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <scope>runtime</scope>
</dependency>
<!-- Normally this jar would be listed in dependencies but in my case causes log4j ERROR. -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>${slf4j.version}</version>
    <scope>runtime</scope>
</dependency>

更重要的是,我从spring和其他依赖它的项目中排除了公共日志记录。

(不满意)解决方案: 只有当log4j,slf4j-api,slf4j-log4j12和jcl-over-slf4j jar放在我的WEB-INF / lib目录中时,日志才能正常工作,但只有当jcl-over-slf4不在项目的类路径中时 strong>(即我注释掉最后提到的依赖关系)。

当jcl-overl-slf4j包含在maven依赖项中时(见上文),它不仅被添加到目标的lib目录中,而且还包含在项目的类路径中。它会导致错误。这个jar必须放在lib中,但只有当它没有包含在类路径中时,错误才会消失。 maven-dependency-plugin用于通过将其复制到lib目录并跳过maven依赖来解决这个问题。

这个解决方案显然只是一个解决方法,因为gwt和spring项目的许多标准示例都提到了所有四个jar - log4j,slf4j-api,slf4j-log4j12,jcl-over-slf4j。

你能解释一下为什么它会以这种方式运行吗?如何通过在maven依赖项中正常包含jcl-over-slf4j来解决这个问题?

1 个答案:

答案 0 :(得分:4)

Jetty将org.apache.commons.logging视为系统类,即它从系统类加载器(即类路径)优先于webapp WEB-INF/lib加载它。在您的情况下,org.apache.commons.loggingjcl-over-slf4j提供。因此,webapp中的代码调用Commons Logging,然后从系统类加载器加载,它可能使用类的类加载器(而不是当前的线程类加载器)初始化SLF4J,因此使用来自{的代码。来自系统类加载器的{1}}和slf4j-log4j12。稍后,webapp中的代码调用Log4j(可能通过SLF4J)来初始化日志记录配置,然后它使用来自webapp的log4j的JAR(如预期的那样)。当把所有东西放在一起时,就会出现问题,从不同的类加载器加载类。

现在要解决这个问题:它并不简单。

简单地说,DevMode中的类加载是一团糟(请参阅https://docs.google.com/document/d/1bWfafaPA0m0Z1Swodnx7m3QTv31OdqFkE7aeadN_2BU/edit?usp=sharing我尝试记录它)。

要解决您的问题,您必须在DevMode中使用自己的WEB-INF/lib和您自己的类加载规则,或者更简单地在另一个servlet容器中运行您的webapp(例如ServletContainerLaunchermvn jetty:run,或其他什么)。然后,您将以mvn tomcat7:run模式运行DevMode。

这是一个稍微复杂的设置,但它有一个很大的优势,就是你正好需要SuperDevMode; SuperDevMode今年将取代DevMode(DevMode已经在Firefox中已经死了,在Linux上的Chrome中已经死了 - 基本上它已经死在Linux上了,今年晚些时候其他平台上的Chrome将被删除,只留下一个工作平台:Windows上的Internet Explorer。