问题描述:
启动tomcat,发现tomcat无法启动,catalina.out有如下错误日志:
INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log Closing Spring root WebApplicationContext
SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.listenerStop Exception sending context destroyed event to listener instance of class org.springframework.web.context.ContextLoaderListener
java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFactory
at org.apache.log4j.LogManager.getLogger(LogManager.java:44)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:73)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:270)
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:156)
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:132)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:274)
at org.springframework.web.context.ContextCleanupListener.<clinit>(ContextCleanupListener.java:43)
at org.springframework.web.context.ContextLoaderListener.contextDestroyed(ContextLoaderListener.java:145)
at org.apache.catalina.core.StandardContext.listenerStop(StandardContext.java:4860)
at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5495)
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:224)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:159)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1407)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1397)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
问题分析:
检查lib库下面,发现今天更新过log4j和logback组合,总共有如下包:
slf4j-api-1.7.5.jar
slf4j-log4j12-1.6.1.jar
log4j-1.2.16.jar
log4j-over-slf4j-1.7.5.jar
logback-core-1.1.2.jar
logback-classic-1.1.2.jar
通过查询资料发现,包slf4j-log4j12-1.6.1.jar 和log4j有冲突。
解决方法:
删除后正常,删除这个:slf4j-log4j12-1.6.1.jar
附件常见组合:
log4j+slf4j
slf4j-api-1.7.5.jar
slf4j-log4j12-1.6.1.jar
log4j-1.2.16.jar
slf4j+logback
logback-core-1.1.2.jar
logback-classic-1.1.2.jar
slf4j-api-1.7.5.jar
还记得上次发版本遇到一个jar包冲突的问题,今天有时间和大家分享下:
首先在测试环境和P版线上模拟环境都没有出现这样的问题,在正式版上,运维人员给出的堆栈结果如下:
- [19:56:18.083] Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFactory
- [19:56:18.083] at org.apache.log4j.Logger.getLogger(Logger.java:39)
- [19:56:18.083] at com.focustech.redis.util.JsonUtil.<clinit>(JsonUtil.java:22)
- [19:56:18.083] at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
- [19:56:18.083] at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
- [19:56:18.083] at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
- [19:56:18.083] at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
- [19:56:18.083] at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:82)
- [19:56:18.083] at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:59)
- [19:56:18.083] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:52)
- [19:56:18.083] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:639)
- [19:56:18.083] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:625)
- [19:56:18.083] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
- [19:56:18.083] ... 21 more
对于这样的错误堆栈,我们首先排查了是不是少这个jar包,但是发现其实这个jar包是有的,并且类也是有的,所以我们又继续排查是不是jar包冲突引起的问题,发现应用的pom文件中与该类相关的只有一个这样的类,不会有多个,所以又派出jar包冲突的问题,所以暂时进行的日志的改造,但是结果还是报这样的错误。
就在这个时候我试图到log中查找其他的信息,这个时候发现在容器的system error文件中发现有这样的错误堆栈
- SLF4J: Detected both log4j-over-slf4j.jar AND slf4j-log4j12.jar on the class path, preempting *Error.
- SLF4J: See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.
这个时候我们才发现可能是这两个jar包搞的鬼,所以我百度下了,确实这两个jar包一起会报这样的错误
具体原因该文章分析的很好,可以学习下
http://www.tuicool.com/articles/INveIf
通过这次比较囧的经历,首先,在遇到问题的时候要从多个日志输出文件中去找问题,一般有很多runtime error都打在容器的error日志文件中,其次要多了解一些框架的原理!
可能出现的异常:
发现配置的logback.xml文件没有起作用,于是分析了一下启动log,发现log中出现了SLF4J冲突异常:
- SLF4J: Class path contains multiple SLF4J bindings.
- SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”
原因分析:
既然是冲突,那可能就是项目中依赖了多个不同版本的slf4j类库,那如何分析到底是哪几个类库依赖了slf4j呢?我们可以使用dependency:tree
命令:
$ mvn dependency:tree
解决:
经过依赖tree的分析,发现Zookeeper和Dubbo类库各自都引用了slf4j类库,于是使用<exclusions>
标签排除掉传递依赖。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.8.4</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
其它各种依赖冲突都可以使用这种方式解决。