Dubbo框架升级Log4j2采坑

本文介绍了在将Dubbo框架的日志从log4j升级到log4j2过程中遇到的问题及解决方案。升级后,由于依赖冲突导致控制台出现WARN,部分日志无法打印。解决方法包括引入log4j2依赖,排除非log4j2的日志依赖,以避免冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Apache Log4j 2是Log4j的升级版,它比Log4j 1.x 版本有了很大的性能提升,吸收了LogBack的先进功能,更通过优秀的锁机制、LMAX Disruptor、"无垃圾"机制等先进特性,在性能上全面超越了Log4j和LogBack

升级Log4j2后的项目地址:
https://github.com/ryiann/ssm-dubbo

为什么升级Log4j2,有哪些优点?

  • 日志模板功能
  • 支持异步输出日志
  • 略…具体请查看官方文档

好了,本文的重点也不是介绍Log4j2的优点,本文主要记录下Dubbo框架升级Log4j2的一些坑,所以这里不介绍那么多了


之前使用dubbo框架采用的是log4j日志,自从知道了log4j2的优秀日志模板,在写法上有了改进,就一直念念不忘,今天花了点时间把日志升了下级,不过也遇到了一些坑,升级后,出现log4j、log4j2冲突问题,控制台一直出现以下WARN,一些日志打印不出来

Zookeeper/ZkClient等默认使用log4j的组件无法打印日志

log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).

解决

导入log4j2依赖

按实际情况引入桥接,如果没有使用commons-logging日志,就不用引入log4j-jcl,博主没有引入

	<!--  桥接:告诉Slf4j使用Log4j2  -->
	<!--  https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl  -->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-slf4j-impl</artifactId>
      <version>2.8.2</version>
    </dependency>
    <!-- 桥接:告诉commons-logging使用Log4j2 -->
    <!--<dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-jcl</artifactId>
      <version>2.8.2</version>
    </depen
<think>我们面对的具体问题是:在升级DubboZookeeper后,出现了logback-classic和log4j-slf4j-impl的冲突,导致SLF4J发现多个绑定(multipleSLF4Jbindings)。根据之前的引用和解决方案,我们知道这是由于同时存在两个SLF4J的实现(Logback和Log4j)造成的。关键引用:-引用[3]和[4]显示:启动时警告发现两个绑定,分别是slf4j-log4j12(对应Log4j1)和logback-classic(对应Logback)。但注意,在问题描述中提到的冲突是logback-classic和log4j-slf4j-impl(Log4j2的SLF4J绑定)。所以这里需要澄清:log4j-slf4j-impl是Log4j2的SLF4J绑定,而slf4j-log4j12Log4j1的绑定。但问题中同时出现了log4j-slf4j-impl和logback-classic。解决思路:1.我们需要确保项目中只使用一个SLF4J绑定实现。根据用户需求,可能需要保留Logback(因为logback-classic已经存在),并排除log4j-slf4j-impl;或者反过来。但根据引用[2]中的配置,用户可能更倾向于使用Logback(因为排除了slf4j-log4j12,并且还排除了整个logbackgroup,但这可能是为了排除旧的logback版本,这里需要具体分析)。2.由于升级DubboZookeeper,需要检查它们引入的日志依赖。根据经验,DubboZookeeper可能会传递引入一些日志依赖。3.解决方案:通过Maven的依赖排除,移除冲突的绑定包。具体步骤:步骤1:分析依赖树使用命令:`mvndependency:tree-Dincludes=*:slf4j-*,*:log4j-*,*:logback-*`来查看哪些依赖引入了冲突的日志包。步骤2:根据依赖树,在引入冲突依赖的dependency中添加exclusion。假设我们想使用Logback(即保留logback-classic),那么我们需要排除log4j-slf4j-impl以及任何Log4j1的绑定(如slf4j-log4j12)。同时,注意log4j-over-slf4j(引用[1]中出现)是一个桥接器,用于将Log4j1的API调用重定向到SLF4J,如果我们要使用Logback,这个包是可以存在的,因为它不是绑定实现。但是,如果我们的项目中没有使用Log4j1的API,那么slf4j-log4j12log4j-over-slf4j都不是必须的。重点在于排除所有不是我们想要的绑定。根据引用[5]和引用[2]的示例,我们可以对引入冲突的依赖进行排除。示例:在Zookeeper依赖中排除slf4j-log4j12(这是Log4j1的绑定,但问题中出现了log4j-slf4j-impl,所以可能是Log4j2的绑定。注意,我们可能需要排除的是log4j-slf4j-impl)。因此,我们需要具体分析依赖树。假设依赖树显示,log4j-slf4j-impl是由某个依赖(可能是dubbozookeeper)引入的,那么我们就需要在该依赖中排除它。然而,根据Dubbo3.2.17和Zookeeper3.9.2的官方依赖情况:-Zookeeper3.9.2的依赖中,默认使用Log4j2作为日志框架,因此它会传递引入log4j-slf4j-impl(将SLF4J调用桥接到Log4j2)以及log4j-core等。-Dubbo3.2.17的依赖中,日志部分通常由用户自行配置,但可能传递引入一些日志依赖。因此,解决方案如下:如果我们想要使用Logback,我们必须在整个项目中排除log4j-slf4j-impl(因为它是Log4j2的绑定)以及slf4j-log4j12Log4j1的绑定)。同时,我们需要确保引入logback-classic(作为绑定)以及logback-core。在pom.xml中配置:1.对于dubbozookeeper依赖,排除它们传递引入的日志绑定:```xml<dependencies><!--处理Dubbo的日志依赖:一般Dubbo本身不会直接引入具体的日志绑定,但为了安全可以检查--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo</artifactId><version>3.2.17</version><!--排除可能存在的日志绑定(如log4j-slf4j-impl)--><exclusions><exclusion><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId></exclusion><!--排除Log4j1的绑定--><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions></dependency><!--处理Zookeeper的日志依赖:Zookeeper3.9.2默认使用Log4j2,所以会引入log4j-slf4j-impl--><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.9.2</version><exclusions><!--排除Log4j2的绑定--><exclusion><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId></exclusion><!--排除Log4j1的绑定(可能旧版本中有)--><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion><!--注意:Zookeeper还会传递引入log4j-core(Log4j2的核心),如果我们不使用Log4j2,也可以排除,但注意是否其他组件需要。不过如果排除了绑定,核心库在运行时不会被使用,但为了减少依赖,可以排除--><exclusion><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId></exclusion><exclusion><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId></exclusion></exclusions></dependency></dependencies>```2.显式引入我们想要的日志框架(Logback):```xml<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.11</version></dependency>```步骤3:验证运行项目,观察启动日志是否还有多个绑定的警告。同时,运行`mvndependency:tree`确保冲突的依赖已经被排除。注意:有时其他依赖也可能引入日志绑定,因此要确保整个项目中只有一个绑定。另外,引用[2]中还提到了在Gradle中排除日志整个group的方式,但我们这里是Maven,所以使用exclusion。如果使用Gradle,可以按照引用[2]的配置。总结:1.排除DubboZookeeper依赖中传递引入的日志绑定(特别是log4j-slf4j-impl和slf4j-log4j12)。2.确保引入我们需要的日志实现(这里以Logback为例)。这样,SLF4J将只找到一个绑定(即Logback),冲突解决。相关问题:1.如何检查Maven依赖树以确定冲突的来源?2.在SpringBoot项目中如何统一管理日志依赖?3.SLF4J绑定机制的底层原理是什么?4.Logback和Log4j2哪个性能更好?5.如何在Gradle项目中排除传递依赖?</think> ### 解决方案:解决DubboZookeeper升级后的Logback与Log4j冲突 根据您的依赖升级情况(Dubbo 2.7.15→3.2.17, Zookeeper 3.4.6→3.9.2),结合引用[2][5]的排除方法,以下是分步解决方案: --- ### **根本原因分析** 1. **冲突源头** - Zookeeper 3.9.2 依赖树包含 `log4j-slf4j-impl`[^5] - Dubbo 3.2.17 或其间接依赖可能引入 `logback-classic` - 两者同时存在导致 SLF4J 加载多个绑定实现 2. **错误表现** 启动时会出现警告(如引用[3][4]): ``` SLF4J: Found binding in [jar:.../log4j-slf4j-impl.jar] SLF4J: Found binding in [jar:.../logback-classic.jar] ``` --- ### **解决步骤** #### **1. 强制排除冲突依赖(关键步骤)** 在 `pom.xml` 中对 Zookeeper 依赖添加排除规则: ```xml <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.9.2</version> <exclusions> <!-- 排除Log4j的SLF4J绑定 --> <exclusion> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> </exclusion> <!-- 额外排除旧版Log4j1绑定(如存在) --> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> ``` #### **2. 显式声明Logback依赖** 添加明确版本的Logback依赖(防止被其他依赖覆盖): ```xml <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.11</version> </dependency> ``` #### **3. 验证依赖树** 执行命令检查是否成功排除: ```bash mvn dependency:tree -Dincludes=*:logback-*,*:log4j-* ``` 期望结果: ``` [INFO] org.apache.zookeeper:zookeeper:jar:3.9.2 [INFO] ch.qos.logback:logback-classic:jar:1.2.11 ``` ⚠️ 不应出现 `log4j-slf4j-impl` 或 `slf4j-log4j12` --- ### **补充建议** 1. **Dubbo的日志适配** 如果Dubbo日志未输出,添加适配依赖: ```xml <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-logger-slf4j</artifactId> <version>3.2.17</version> </dependency> ``` 2. **Gradle解决方案** 如使用Gradle(引用[2]): ```groovy implementation ('org.apache.zookeeper:zookeeper:3.9.2') { exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl' exclude group: 'org.slf4j', module: 'slf4j-log4j12' } configurations { compile.exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl' } ``` --- ### **验证成功标准** 应用启动时 **无** 以下警告: ```log SLF4J: Class path contains multiple SLF4J bindings... ``` 且日志输出正常(如Logback配置文件生效) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值