发布网友 发布时间:2024-09-28 15:14
共1个回答
热心网友 时间:2天前
一、前言在进行Java开发时,通常我们会选择Slf4j作为日志门面,但日志实现却不尽相同。如果系统运行中同时存在多个日志实现,就会出现类似下图的Warning。
我们知道SpringBoot默认使用的日志实现是Logback,因此我们尝试在项目中引入Log4j的依赖时,就复现了上图的报错。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency>上图报错告知我们存在多个SLF4Jbingdings,分别位于logback和log4j包中,有两个StaticLoggerBinder。
我们知道使用Slf4j,需要LoggerFactory.getLogger()方法获取实例。
importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;privatefinalLoggerlogs=LoggerFactory.getLogger(xxx.class);我们就可以通过这个作为入口,去看看源码的实现。如下图所示,我标注了需要关注的核心代码。
(1)调用getILoggerFactory()方法得到LoggerFactory。
(2)对于首次调用,INITIALIZATION_STATE应该是UNINITIALIZED,所以进入初始化的逻辑,调用方法performInitialization()。
(3)调用bind()方法。
(4)如果不是isAndroid(),调用
findPossibleStaticLoggerBinderPathSet()方法,故名思意,查找可能的staticLoggerBinder,注意这里返回的类型是SET,即可能是多个。
(5)在findPossibleStaticLoggerBinderPathSet()这个方法内,首先通过classLoader加载了org/slf4j/impl/StaticLoggerBinder.class这个类的path,它可能存在多个,因此使用了while获取了所有的path,并最终返回。
(6)reportActualBinding()方法会校验SET的size,如果大于1,就会打印出一开始我们看见的Warning了。
解决思路就是将你不想要的日志实现从依赖包中排除掉即可,通过IDEA提供的Diagrams能够非常方便的查看项目中的依赖关系。
打开项目的POM文件,右键选择Diagrams->ShowDependencies
假设我们想要排除logback依赖,使用log4j。Ctrl+F搜索logback,可以找到引用该依赖的树形结构。
点击窗口左上角的下图中的这个图标,可以只看当前选中的这个依赖的关系。
选中后效果如下:
如上图所示,logback由spring-boot-starter-logging引入,最顶层是由spring-boot-starter-web和spring-boot-starter-test引入。
我们尝试在spring-boot-starter-web中排除该依赖,应该就可以了。如果排出后重新搜索仍然存在logback依赖,则重复执行排除的操作。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency>四、总结日志框架冲突特别对于新手来说处理起来比较头疼,因为涉及到了日志接口和日志实现。
我们推崇的应该是面向接口编程,因此我们大到开源项目,小到公司的公共jar包,应当合理利用Maven的传递机制。具体的日志实现不应该传递出去,避免影响到调用的下游方。
<optional>true</optional>作者:Jitwxs