Java项目依赖版本由构建工具自动解析依赖图决定,可通过dependencyManagement统一约束多模块版本、exclusions排除传递依赖、BOM管理版本等机制精准控制。

Java项目依赖版本不是靠手动改jar包决定的,而是由构建工具在解析依赖图时自动选择——你真正能控制的,只有声明的版本范围和冲突解决策略。
用 dependencyManagement 统一约束子模块版本
多模块项目里,各 pom.xml 单独写 <version> 容易不一致。把公共依赖版本提到父POM的 <dependencyManagement> 块里,子模块只需声明 <groupId> 和 <artifactId>,不写 <version> 也能继承版本。
注意:这不会引入依赖,只是“约定”;子模块仍需在 <dependencies> 中显式声明才能生效。
-
<scope>、<exclusions>等配置在<dependencyManagement>中也有效,会被子模块继承 - Spring Boot 的
spring-boot-dependenciesBOM 就是靠这个机制统一管理数百个依赖版本 - 若子模块想覆盖父级版本,直接在自己的
<dependencies>里写死<version>即可(但不推荐)
理解 mvn dependency:tree 输出中的版本来源
执行 mvn dependency:tree -Dverbose 是排查版本冲突最直接的方式。关键看每行末尾的括号内容:
立即学习“Java免费学习笔记(深入)”;
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
-
(omitted for duplicate):该依赖被更高优先级的同 artifactId 版本替代了 -
(omitted for conflict with X.X.X):当前路径选了 X.X.X,其他路径有不同版本但被丢弃 - 没括号的行 = 实际打进包里的版本
版本谁胜出,取决于 Maven 的“最近优先”原则:依赖路径越短,优先级越高。不是 pom 里声明顺序,也不是字母顺序。
用 <exclusions> 或 <optional> 主动切断传递依赖
第三方库常带一堆你不想要的传递依赖(比如某个日志桥接器强制拉低 SLF4J 版本)。这时不能只靠 dependencyManagement,得主动干预:
- 在引入该第三方依赖时,用
<exclusions>显式排除掉有问题的传递依赖 - 若你自己发的库希望下游可选依赖(如测试工具类),在自己的
pom.xml里给对应依赖加<optional>true</optional>,它就不会传递给使用者 -
<exclusions>不会阻止依赖被其他路径引入,只是断开当前这条路径
Gradle 用户注意 platform 和 enforcedPlatform 的区别
Gradle 没有 dependencyManagement,但可用 BOM 控制版本:
-
implementation platform('org.springframework.boot:spring-boot-dependencies:3.2.0'):仅建议版本,下游仍可覆盖 -
implementation enforcedPlatform('...'):强制锁定,任何显式声明的冲突版本都会被忽略(类似 Maven 的dependencyManagement+force=true) - BOM 文件本身必须是
type=pom,否则 Gradle 无法解析其<dependencyManagement>内容
真正难的是当多个 BOM 同时存在时的版本叠加逻辑——Gradle 默认取最后一个,而 Maven 是合并所有 dependencyManagement 块后按 POM 层级覆盖。这点差异经常导致跨工具构建结果不一致。

















