在网络上的几个来源中提到了这个问题,但我无法通过那里提供的解决方案来解决它。
问题: 发出 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来解决这个问题?
答案 0 :(得分:4)
Jetty将org.apache.commons.logging
视为系统类,即它从系统类加载器(即类路径)优先于webapp WEB-INF/lib
加载它。在您的情况下,org.apache.commons.logging
由jcl-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(例如ServletContainerLauncher
或mvn jetty:run
,或其他什么)。然后,您将以mvn tomcat7:run
模式运行DevMode。
这是一个稍微复杂的设置,但它有一个很大的优势,就是你正好需要SuperDevMode; SuperDevMode今年将取代DevMode(DevMode已经在Firefox中已经死了,在Linux上的Chrome中已经死了 - 基本上它已经死在Linux上了,今年晚些时候其他平台上的Chrome将被删除,只留下一个工作平台:Windows上的Internet Explorer。