1. 问题描述
控制台中可以正常运行,不会报如下错误,但打成jar包会显示错误,如下:
C:\Users\1234\Desktop\eda-win\user>java -jar svc_user-1.0-SNAPSHOT.jar
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/1234/Desktop/eda-win/user/svc_user-1.0-SNAPSHOT.jar!/BOOT-INF/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/1234/Desktop/eda-win/user/svc_user-1.0-SNAPSHOT.jar!/BOOT-INF/lib/logback-classic-1.2.3.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.slf4j.impl.Log4jLoggerFactory]
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.Log4jLoggerFactory loaded from jar:file:/C:/Users/1234/Desktop/eda-win/user/svc_user-1.0-SNAPSHOT.jar!/BOOT-INF/lib/slf4j-log4j12-1.7.25.jar!/). If you are using WebLogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.impl.Log4jLoggerFactory
at org.springframework.util.Assert.instanceCheckFailed(Assert.java:637)
at org.springframework.util.Assert.isInstanceOf(Assert.java:537)
at org.springframework.boot.logging.logback.LogbackLoggingSystem.getLoggerContext(LogbackLoggingSystem.java:274)
at org.springframework.boot.logging.logback.LogbackLoggingSystem.beforeInitialize(LogbackLoggingSystem.java:99)
at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationStartingEvent(LoggingApplicationListener.java:191)
2. 问题分析
- 根据日志中SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
打开slf4j的官方解释文档
Multiple bindings were found on the class path
SLF4J API is designed to bind with one and only one underlying logging framework at a time. If more than one binding is present on the class path, SLF4J will emit a warning, listing the location of those bindings.
When multiple bindings are available on the class path, select one and only one binding you wish to use, and remove the other bindings. For example, if you have both slf4j-simple-2.0.0-alpha0.jar and slf4j-nop-2.0.0-alpha0.jar on the class path and you wish to use the nop (no-operation) binding, then remove slf4j-simple-2.0.0-alpha0.jar from the class path.
The list of locations that SLF4J provides in this warning usually provides sufficient information to identify the dependency transitively pulling in an unwanted SLF4J binding into your project. In your project's pom.xml file, exclude this SLF4J binding when declaring the unscrupulous dependency. For example, cassandra-all version 0.8.1 declares both log4j and slf4j-log4j12 as compile-time dependencies. Thus, when you include cassandra-all as a dependency in your project, the cassandra-all declaration will cause both slf4j-log4j12.jar and log4j.jar to be pulled in as dependencies. In case you do not wish to use log4j as the the SLF4J backend, you can instruct Maven to exclude these two artifacts as shown next:
简单翻译一下如下:
在类路径上找到多个绑定
SLF4J API设计为一次仅绑定一个底层日志框架。如果类路径上存在多个绑定,则SLF4J将发出警告,列出这些绑定的位置。
当类路径上有多个绑定时,请选择一个且仅选择一个您要使用的绑定,然后删除其他绑定。例如,如果您在类路径上同时拥有slf4j-simple-2.0.0-alpha0.jar和slf4j-nop-2.0.0-alpha0.jar,并且您希望使用nop(无操作)绑定,则删除类路径中的slf4j-simple-2.0.0-alpha0.jar。
SLF4J在此警告中提供的位置列表通常提供足够的信息,以标识依赖关系,该依赖关系可传递地将不需要的SLF4J绑定拉入项目。在声明不适当的依赖项时,请在项目的pom.xml文件中排除此SLF4J绑定。例如,cassandra-all 0.8.1版将log4j和slf4j-log4j12都声明为编译时依赖项。因此,当在项目中包括cassandra-all作为依赖项时,cassandra-all声明将导致slf4j-log4j12.jar和log4j.jar都作为依赖项被拉入。如果您不想将log4j用作SLF4J后端,则可以指示Maven排除这两个工件,如下所示:
- 问题的原因找到了,SLF4J作为一个日志接口,它每次只能绑定有且仅有一个日志实现类;我上述的这个问题即是同时绑定了logback和log4j这两种具体日志实现;
- logback 日志的开发者和log4j 的开发者据说是一波人,而springboot 默认日志是,较新的logback 日志。但是在以前流行的日志却是log4j ,而且很多的第三方工具都含有log4j 得引入。而我们在项目开发中,难免会引入各种各样的工具包,所以,基本上springboot 项目,如果不注意,肯定会出现这种冲突的。
- 最恶心的是,你在开发工具中运行或者用外置的tomcat将ROOT.jar去放入webapps文件夹下去启动,一般都不会有问题,但如果打成jar包,那么问题就出现了;
2. 问题解决
搜索查到解决方法
- 通过编译器中图形化的依赖来查看和排除
直接看jar实在太多,有点晕,后发现随意点击一个jar,可查看冲突的或者重复的
然后看到的似乎简化了一点儿,但还是没发现我要的
小结:到这里,我突然好像想明白了,这里冲突的没看到与日志有关的,再回头想想,冲突指的是同一个jar,却引用了多个版本的,而我们遇到的这个问题不是一个jar引用了多个版本,而是对于SLF4J这个日志框架,只能有一个实现类,而网上查找的这种方法去查看实际上是看不出来什么问题的
难道这个问题就解决不了了吗,啊啊啊?
- 我开始尝试用最愚蠢的方式,那就是把引用的jar,查看全部的引入坐标,看里面哪里可能引用了日志有关的,然后反复排除和打包,缩到最简,最后终于可以打出不报日志错误的包了!
好在最后问题解决了,被困扰了好久!长舒一口气!
3. a little trick
原本jar是在linux服务器上运行,为了快速测试jar,我直接在windows上测试了,但如果在window中测试打开jar的时候闪退,日志信息都来不及看,这时可以考虑在bat文件后面增加"pause",这时如果日志报错会停下来的,很实用的小技巧哈!