最常用且最精准的解决方式是直接在pom.xml中用切断不需要的传递依赖;需先用mvn dependency:tree -dverbose或-dincludes定位冲突源头,在引入该依赖的块内精准排除,仅写groupid和artifactid,排除后须验证版本唯一性及功能完整性,并建议配合dependencymanagement统一版本。

直接在 pom.xml 中用 <exclusions></exclusions> 切断不需要的传递依赖,是最常用也最精准的解决方式。关键不是“排除越多越好”,而是“排除得准、排得稳”。
明确谁引入了冲突版本
先运行命令定位源头:
-
mvn dependency:tree -Dverbose:显示所有被裁剪(omitted for conflict)和被忽略的节点,不漏隐藏路径 -
mvn dependency:tree -Dincludes=groupId:artifactId:聚焦查看某个包(如org.apache.logging.log4j:log4j-core)被哪些依赖层层带入
例如输出中看到:
[INFO] | \- org.springframework.boot:spring-boot-starter-logging:jar:2.7.18:compile
[INFO] | \- org.apache.logging.log4j:log4j-core:jar:2.17.2:compile
[INFO] \- com.example:legacy-sdk:jar:1.2.0:compile
[INFO] \- org.apache.logging.log4j:log4j-core:jar:2.11.2:compile (omitted for conflict)
说明 legacy-sdk 带来了旧版 log4j-core,而 Spring Boot 引入了新版——冲突就在这里,排除目标应是 legacy-sdk 的传递依赖。
在对应依赖块内写 exclusion
不是全局删包,而是“在哪引入的,就在哪排除”:
- 只写
<groupid></groupid>和<artifactid></artifactid>,不用写<version></version> - exclusion 只作用于当前
<dependency></dependency>的传递链,不影响其他依赖 - 如果一个依赖多次出现(比如多个模块都用了 fastjson),需在每个声明处分别排除
示例:
<dependency><groupid>com.example</groupid><artifactid>legacy-sdk</artifactid><version>1.2.0</version><exclusions><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>
排除后必须验证效果
排除不是一劳永逸,要确认它真正生效:
- 再次执行
mvn dependency:tree -Dincludes=org.apache.logging.log4j:log4j-core - 检查输出里是否只剩一个版本(且是你期望的版本),且不再出现 omitted for conflict
- 启动应用,重点测试原本报错的功能点(如日志输出、JSON 序列化等),避免因排除导致功能缺失
注意:若排除后某功能异常(比如 legacy-sdk 内部硬编码调用了 log4j 2.11 特有 API),说明不能简单排除,需升级 SDK 或改用适配层。
配合 dependencyManagement 更稳妥
单纯 exclusion 容易遗漏或维护困难,建议搭配 <dependencymanagement></dependencymanagement>:
- 在父 POM 或当前 POM 的
<dependencymanagement></dependencymanagement>中声明统一版本(如 log4j-core 2.20.0) - 这样即使某个依赖没被排除,Maven 也会按管理版本拉取,降低冲突概率
- exclusion + version lock 双保险,既切断干扰路径,又兜底保障版本一致性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











