2018-08-19 Could not initialize class org.apache.log4j.Log4jLoggerFactory

现象:正常运行的项目从测试环境部署到生产容器云报错

Caused by: java.lang.NoClassDefFoundError: Could not initializeclassorg.apache.log4j.Log4jLoggerFactory

项目缺少log4j依赖包?不可能,在测试环境与本地都能正常启动。再仔细看了日志,


看来是log4j-over-slf4j.jar 和 slf4j-log4j12.jar 不能在同一个class path。

解决:

利用maven找jar包冲突,执行依赖树命令,用 omitted for conflict with 检索。

mvn -X compile dependency:tree -Dverbose >a.log

找出冲突的jar包,exclude掉即可。

为什么之前Jenkins上能正常启动?猜测是tomcat8和tomcat7的区别吧。

遇到问题看日志信息还是非常重要!


https://www.tuicool.com/articles/INveIf log4j-over-slf4j与slf4j-log4j12共存stack overflow异常分析 - 推酷


了解下现在java的日志体系


java日志体系

从图可以得知java日志体系分为日志门面接口、绑定桥接以及日志框架。Java日志框架有很多种,最简单的是Java自带的java.util.logging,而最经典的是log4j,后来又出现了一个比log4j性能更好的logback,其他的日志框架就不怎么常用了。应用程序直接使用这些具体日志框架的API来满足日志输出需求当然是可以的,但是由于各个日志框架之间的API通常是不兼容的,这样做就使得应用程序丧失了更换日志框架的灵活性。java程序使用这些日志框架实现日志的输出当然是可以的,但是这些日志框架之间是不兼容的。

   比起直接使用日志框架api,更合理的是使用日志门面接口。但是日志门面接口又不能直接输出日志,底层还是调用巨头的日志框架实现。由于日志框架非常多,而且相互之间不兼容,所以就需要绑定和桥接,需要找到对应的桥接器。但不是所有的门面接口都需要桥接器才能调用日志框架。也可以直接调用。



如果只是上面这样的方式,还不会出现问题。但是实际上还有另外一类桥接器,它们的作用跟上面的恰好相反,它们将其它日志框架的API转调到slf4j的API上。下图来自slf4j官网文档 Bridging legacy APIs :


发现几乎所有其他日志框架的api都可转调回slf4j。但是有一个问题,转调回的日志框架,不能与slf4j当前桥接的日志框架相同。这个限制就是为了防止A-to-B.jar跟B-to-A.jar同时出现在类路径中,从而导致A和B一直不停地互相递归调用,最后堆栈溢出。目前这个限制并不是通过技术保证的,仅仅靠开发者自己保证,这也是为什么slf4j官网上要强调所有合理的方式只有上图的三种情形。可以发现log4j-over-slf4j与slf4j-log4j12的组合会发现类似的异常。slf4j官网还指出了另外一对: jcl-over-slf4j.jar和slf4j-jcl.jar

你可能感兴趣的:(2018-08-19 Could not initialize class org.apache.log4j.Log4jLoggerFactory)