6.1 Maven 与 Spring:框架级依赖治理协同


文档摘要

6.1 Maven 与 Spring:框架级依赖治理协同 本节摘要:Spring Boot 用 starter(带默认配置的依赖组)与 BOM(框架级版本仲裁表)两个构件把依赖治理打包给应用。应用侧的正确姿势是导入 BOM 而非逐个声明版本,覆盖版本用属性机制走仲裁正门,repackage 目标负责产出可执行 jar。本节讲清两套治理体系的衔接协议。 starter 不是依赖,是"依赖套餐" risk-engine 引入 Spring Boot 的第一天,POM 里只多了一个声明: 一个 starter 背后是一整棵精心调配的依赖树:web 场景带容器、JSON 处理、校验、日志绑定,版本之间经过框架团队的兼容性矩阵验证。

6.1 Maven 与 Spring:框架级依赖治理协同

本节摘要:Spring Boot 用 starter(带默认配置的依赖组)与 BOM(框架级版本仲裁表)两个构件把依赖治理打包给应用。应用侧的正确姿势是导入 BOM 而非逐个声明版本,覆盖版本用属性机制走仲裁正门,repackage 目标负责产出可执行 jar。本节讲清两套治理体系的衔接协议。

starter 不是依赖,是"依赖套餐"

risk-engine 引入 Spring Boot 的第一天,POM 里只多了一个声明:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- 没写版本 版本从哪来?下一小节揭晓 --> </dependency>

一个 starter 背后是一整棵精心调配的依赖树:web 场景带容器、JSON 处理、校验、日志绑定,版本之间经过框架团队的兼容性矩阵验证。starter 的语义是"场景"而不是"库"——你要的是 web 能力,而不是某几个具体的 jar。这种打包方式把传递依赖从负债变成了产品:框架团队替你做了第 3 章的大量仲裁工作,你收到的是一份配平过的组合。

但配平不等于免检。starter 的树照样会与你的其他依赖相遇——第 3.2 节的 Jackson 冲突战例,根源正是 starter 传递树与业务依赖的版本相遇。框架级的仲裁与团队级的仲裁是两层制度,衔接协议在 BOM。

BOM:框架把仲裁表递给你

Spring Boot 的版本决策全部集中在 spring-boot-dependencies 这份 BOM 里:几百个常用构件的版本,按兼容矩阵配平。接入方式就是第 3.3 节学的 import:

<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.7.14</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

导入之后,全部 starter 与常用第三方库(Jackson、日志、持久层)的版本都有了裁决来源,业务 POM 里一个版本号都不用写。要覆盖个别版本时,走属性机制而不是硬写版本字面量

<properties> <!-- BOM 内部用同名属性定义版本 覆盖属性即覆盖裁决 --> <jackson-bom.version>2.13.5</jackson-bom.version> </properties> <!-- 效果:Jackson 全家升到 2.13.5 其余仍按 BOM 裁决 -->

硬写版本字面量(在 dependency 里直接写 version)也能覆盖,但它绕开了"属性即版本"的单一事实源——三个月后没人记得这个版本为什么是手写的。属性覆盖则留下明确的覆盖点,配合第 3.3 节的评审纪律,可审计可回溯。

⚠️ 常见坑:导入多份框架 BOM 时顺序随意,版本裁决变成"谁在前谁说了算"的运气题。正确姿势沿用第 3.3 节的指挥链:团队平台 BOM 压前(终极裁决权),框架 BOM 随后,两份 BOM 冲突的构件必须显式钉在平台 BOM 里并写注释说明理由。

repackage:可执行 jar 的装配

spring-boot-maven-plugin 的核心目标是 repackage:把普通 jar 重新装配成"内嵌容器与全部依赖的可执行 jar":

<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin>
mvn clean package # 输出关键行: # Building jar: target/risk-engine-2.3.0.jar 原始瘦 jar 更名为后缀的原始件 # Replacing main artifact with repackaged archive 主产物替换为内嵌依赖的可执行件 # 启动方式:java -jar risk-engine-2.3.0.jar

装配细节里有个与 6.2 节相关的伏笔:repackage 产物的内部结构是分层的(依赖、应用类、资源分区存放),这个结构让后续的镜像分层打包成为可能。另外注意 repackage 只该发生在最终交付模块——公共库模块挂上它,使用方会把你的库当可执行件处理,经典配置事故。

FAQ:三个高频协同问题

业务依赖与 starter 传递树冲突了,先动谁?

先打 verbose 树确认冲突对,再判断:若业务需要更新版本,用属性覆盖走 BOM 正门;若 starter 侧版本就是对的,修业务侧声明。永远不要用广撒网 exclusion 对付 starter 的传递树——你会拆掉框架的配平组合,报错在很远处开花。

starter 里的某个依赖我完全用不上,能排除吗?

可以精确排除(点名单个构件),但要评估替代品:比如不想要内嵌容器,换用为这个场景准备的 web 轻量变体 starter,比手工排除更稳。框架提供的"正门变体"优先于手工裁剪。

为什么我的版本覆盖没生效?

九成是覆盖点写错了层级:属性覆盖要求覆盖 BOM 使用的同名属性,名字差一点都不行;另一成是覆盖发生在子 POM 而导入在父 POM,属性解析顺序不如预期。诊断武器仍是第 1.4 节的有效 POM——搜索目标版本号的来源,一秒钟出真相。

战报小结

  • starter 是场景套餐:框架团队配平过的依赖树,传递依赖从负债变产品,但与业务依赖的相遇仍按第 3 章规则裁决;
  • BOM 是衔接协议:import 导入框架仲裁表,业务 POM 零版本号,覆盖走属性机制留审计痕迹;
  • 多 BOM 有指挥链:平台 BOM 终极裁决在前,框架 BOM 在后,冲突显式钉版本加注释;
  • repackage 只给交付模块:内嵌装配发生在终点站,公共库挂它是配置事故;
  • repackage 的分层结构是伏笔:为 6.2 节的镜像分层打包准备好了内部结构。

jar 已可执行,下一站装进容器——6.2 节讲多阶段构建与分层打包:怎么让镜像体积与构建缓存同时听话。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U