jianghuchuanke 2019-06-29
spring-boot
项目,启用log4j2
后,报以下错误:
SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/Users/panjie/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.7/log4j-slf4j-impl-2.7.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/Users/panjie/.m2/repository/ch/qos/logback/logback-classic/1.1.11/logback-classic-1.1.11.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
原因:一个接口,被两个实现类实现了。然后,程序在启动获取时,只想获取一个。
这个接口是:org.apache.logging.slf4j.Log4jLoggerFactory
两个实现类分别是:ch/qos/logback/logback-classic/1.1.11/logback-classic-1.1.11.jar!/org/slf4j/impl/StaticLoggerBinder
与org/apache/logging/log4j/log4j-slf4j-impl/2.7/log4j-slf4j-impl-2.7.jar!/org/slf4j/impl/StaticLoggerBinder.class
可以在idea中使用ctrl + o, 然后输入StaticLoggerBinder
,即可定位到两个实现类。然后在实现类中,按alt + f1
再回车,便可以定位到引用的包。
定位两个包如下:
apache
ch.qos
我们发现两个实现类,都是maven
替我们引入的,所以需要在maven
的配置文件上下手,排除一个。
pom.xml
中,哪行依赖引入的。http://www.slf4j.org/codes.html#multiple_bindings,应该是这个问题发生的频率比较高,所以官网上专门对其进行了说明。不过官方在讲,某一个包中引用了多个,然后加入排除,与我们当前面临的情况不同。
打开pom.xml
,在文件内容上,右键,选择 Diagrams
-> show dependencies...
,ctrl + f
输入logback-classic
按图的关系,我们发现,原来是由pdftest
引入的。
你也可以直接双击pdftest
或是logback-classic
这两个小方框,来找到其实对应引入的语句。
在pom.xml
中找到pdftest
, 并添加排除
<!--itextpdf test--> <dependency> <groupId>com.itextpdf</groupId> <artifactId>pdftest</artifactId> <version>${itextpdf.version}</version> <exclusions> <exclusion> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </exclusion> </exclusions> </dependency>
启动单元测试
以前的错误消息了,但新的错误如下:
java.lang.NoClassDefFoundError: ch/qos/logback/classic/turbo/TurboFilter
说明,方向可能错误,恢复代码。继续猜原因。
logback-classic
中的实现类,但是:pdftest
在运行时,却指定了需要logback-classic
中的实现类,所以就报错了。而前面之所以报找到了多个multiple
的错误,由于报错的代码所在的包:
logback-classic
还有一个),所以报错。按照这个思想,我们换一种解法;
那么,我们换一种解法:
再次启动,错误消失。
SLF4JLogFactory
在初始化时,会扫描所有的实现类,所以发现有多个,就会报错。我们在以入其它的包时,不巧的是,引入了一个实现相同接口Log4jLoggerFactory
的实现类。加上sfl4j
本身又自己带了一个过来,结果就有两个了,所以出错了。
最后的解决方案就是去一个,去哪个呢?通过实验,我们发现去除sfl4j
自带的,不会出现问题。如果去除另一个,由于另一个的类,直接被其它类实例化了,去除了则会报错。
收获: