Maven 依赖冲突常常表现得很诡异:本地能跑,测试环境报 NoSuchMethodError;升级一个 starter 后,另一个组件突然初始化失败。真正的问题通常不是“包坏了”,而是 classpath 上出现了不兼容版本。
先画出依赖树
第一步运行 mvn dependency:tree,把冲突包的来源找出来。重点看 groupId、artifactId、版本号和路径深度。Maven 默认采用“路径最近优先”,同一深度时按声明顺序决定,这会让间接依赖的版本不符合直觉。
如果输出太多,可以用 includes 过滤目标包。比如只看 Jackson、Netty、Guava、Spring 相关依赖,先把可疑范围缩小。
再确认运行时版本
依赖树显示的是构建视角,运行时还要看 fat jar、容器、插件和外部 lib 目录。某些老项目会把 jar 放在服务器固定目录里,导致本地和线上 classpath 不一致。
遇到 ClassNotFoundException、NoSuchMethodError、NoSuchFieldError 时,要把报错类所在 jar 和实际版本查出来,而不是盲目升级所有依赖。
排除要尽量局部
解决冲突可以显式声明版本、使用 dependencyManagement 或在具体依赖上 exclusions。优先选择能解释清楚的局部排除,不要为了一个冲突把大范围依赖排掉。
Spring Boot 项目尽量跟随 BOM 管理版本。手动覆盖版本时,要说明原因和退出条件,否则后续升级会变成猜谜。
验证不能只编译通过
依赖冲突修复后,至少要跑单元测试、启动测试和受影响功能的 smoke test。编译通过只能证明代码能构建,不能证明运行期方法签名、序列化行为和自动配置都兼容。
定位 Maven 冲突的关键是证据链:依赖树告诉你谁带来的,运行时版本告诉你谁真正生效,测试告诉你修复是否覆盖风险。




