先介绍一个项目背景、框架使用的是公司在 Spring Boot 、Zookeeper等框架上自己封装的一个自研框架。第一次启动这个项目的时候、就报了如下的错误
比较令人意外的是、只有我启动时出现了这个错误。而其他开发同事并没有出现这个问题。
其实当时解决这个问题还是花费了不少的时间、第一个对这个项目不熟悉、第二个对公司自研的框架不熟悉、第三个当时没有准确地认识到问题的根本(其实是对日志框架的不熟悉)。其实第三个是最直接的原因。
Java 中日志常用有
- Logback
- Log4j
- Log4j2
- commoms-logging (JCL)
- JDK自带的 java.util.logging (JUL)
如今使用比较多的是 Logback 和 Log4j2
jcl-over-slf4j、log4j-over-slf4j、jul-to-slf4j 是用来把日志框架的 API 桥接到 SLF4J API 的。这样一来、即便你的程序中使用了各种日志 API记录日志。最终都可以桥接到 SLF4J 门面 API。
而 slf4j-jcl、slf4j-log4j12、slf4j-jdk14 则是 slf4j 用来适配不同的日志框架的,作为一个适配器。因为 Logback 本身就是按照 SLF4J API 标准实现的、因此就不需要适配。
其实为啥有桥接又有适配呢、如果一些旧的项目本来使用的是 log4j、但是我现在想着的是换一个日志框架、但是改动项目中的日志相关的代码又太多了、所以这个时候我们只需要将日志桥接到 SLF4J、然后再选择另外的日志框架、比如是 Logback。但是这个时候你不能再次通过SLF4J适配到 Log4j,因为这样就会产生死循环。log4j-over-slf4j 和 slf4j-log4j12 同时存在是会有问题的。
Spring Boot 使用的日志框架是 Logback,在 spring-boot-starter模块中有个叫 spring-boot-starter-logging的模块
可以看到其又依赖了 logback-classic(包含了 SLF4J和Logback日志框架)和桥接的jar、log4j-to-slf4j 用于实现 Log4j2 API 到 SLF4J 的桥接,jul-to-slf4j 则是实现 java.util.logging API 到 SLF4J 的桥接
我们再来看下 zk的依赖
我们可以发现 zk 依赖着 log4j、slf4j-log4j12,按上面说的这不仅会导致一个死循环、还会导致 SLF4J 不知道使用 logback 还是 log4j。
那么是不是把log4j、slf4j-log4j12 都 exclusion 就可以了、对的。我当时解决开头的问题的时候就是只是移除掉了slf4j-log4j12 的。只要断了 SLF4J 和 log4j的 关联就可以了。
至于当时为啥很久没解决呢、一是怀疑自己的环境有问题、因为多个同事都没出现这个问题、就我一个。第二就是项目中用到的框架是被平台封装过的、最终找到zk依赖。第三个是没有使用 maven helper这个插件、没办法、资源限制、不能用。
就这样吧!