一.先说一个场景?
很多从单体应用转型微服务的同学都会遇到这样一个尴尬的场景:
刚开始拆分单体项目时,每新建一个微服务(比如把单体项目的菜单功能单独拆成
menu-service微服务),都要去原来的单体项目里翻pom.xml,把Spring Boot、MyBatis、MySQL等依赖的版本号一个个复制过来。不仅麻烦,而且一旦要升级版本(比如Spring Boot从2.7升到3.0),你得去几十个微服务里逐个修改版本号,简直是"灾难现场"。
其实,成熟的微服务架构早就解决了这个问题。 今天我们就来聊聊,如何通过**"统一父工程 + BOM模式"**,彻底解放双手,实现依赖版本的"中央集权"
思考:什么是BOM?
BOM 是 Bill of Materials(物料清单)的缩写,在微服务架构中,它指代一份特殊的 Maven POM 文件。这份文件充当了依赖版本的"中央集权"角色,通过
<dependencyManagement>集中定义了所有第三方库的统一版本号。引入 BOM 后,各个微服务模块在声明依赖时无需再指定版本号,从而确保了整个系统依赖版本的一致性,有效避免了版本冲突,并极大地简化了后续的升级与维护工作。
二.核心思路:建立"依赖联邦"
不要让你的微服务直接继承Spring Boot的官方Parent,而是继承你们项目组自定义的Parent。
这个自定义Parent负责统一管理所有依赖的版本。微服务只需要"听话"继承它,就能自动获得所有标准依赖版本,无需自己维护。
三.实战演示
1.创建一个专门的"版本管理工程"(BOM项目)
首先,创建一个空的Maven项目,不包含任何Java代码,只包含一个pom.xml。我们称之为myproject-bom。
它的作用是:定义所有微服务需要用到的第三方库版本(如MySQL, Redis, Hutool等)以及Spring Cloud组件的版本。


①定义BOM项目自身的坐标
XML
<!-- 1.定义BOM项目自身的坐标-->
<groupId>com.casually</groupId>
<artifactId>myproject_bom</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging><!--pom就表明该项目只是依赖版本清单,即BOM项目,本身不会打jar、war包-->
②添加说明信息(这个不写也没事,但是为了提高可读性)
XML
<!-- 2.添加说明信息(这个不写也没事,但是为了提高可读性)-->
<name>myproject_bom</name>
<description>这是微服务项目的BOM项目(即:依赖清单,统一管理所有依赖的版本)</description>
③依赖版本号变量定义(更加灵活,拒绝硬编码)
注意:像spring-boot.version这种变量名,是自定义的变量名,你自己知道是啥意思就行,写成123.version也行
XML
<!-- 3.依赖版本号变量定义(拒绝硬编码)-->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<java.version>17</java.version>
<!-- Spring Boot Version -->
<spring-boot.version>3.3.3</spring-boot.version>
<!-- Third Party Dependencies Version -->
<mysql.version>8.0.28</mysql.version>
<mybatis-spring-boot.version>3.0.3</mybatis-spring-boot.version>
<pagehelper.version>1.4.6</pagehelper.version>
<aliyun-oss.version>3.17.4</aliyun-oss.version>
<jaxb.version>2.3.3</jaxb.version>
<spring-security.version>3.1.5</spring-security.version>
<spring-mail.version>3.1.5</spring-mail.version>
<spring-data-redis.version>3.2.7</spring-data-redis.version>
<jjwt.version>0.9.1</jjwt.version>
<pdfbox.version>2.0.24</pdfbox.version>
<langchain4j.version>1.0.1-beta6</langchain4j.version>
<fastjson.version>2.0.38</fastjson.version>
<nacos.version>2023.0.1.0</nacos.version>
<!-- Plugin Version -->
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
</properties>
④核心配置:<dependencyManagement>
这是 BOM 的核心。
注意:这里只声明依赖,不引入依赖。
说白了就是:我(父工程)手里有所有的版本号(定标准),但我手里没有 jar 包(不占内存)。你们(子模块)谁想要,就自己伸手拿,拿了就是标准版,不用问版本是多少。
相当于一本书的书单,子项目要是需要某个依赖,直接引入就行,也不用写版本号,因为这里就给规定好了,哪个依赖是哪个版本。
XML
<!-- 4.核心配置:<dependencyManagement>-->
<dependencyManagement>
<dependencies>
<!-- Spring Boot BOM (作为基础,这个在单体项目中不存在,属于是BOM项目的特色了) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version><!--这就用到了上一步定义的依赖变量-->
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 然后把单体项目的依赖,一个一个地弄进来就行了-->
<!-- Web开发-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version> <!-- 请使用最新稳定版 -->
<scope>compile</scope> <!-- 或 optional -->
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot.version}</version>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper.version}</version>
</dependency>
<!-- 阿里云 OSS -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun-oss.version}</version>
</dependency>
<!-- JAXB (Java 17 需要) -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>${jaxb-runtime}</version>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>${spring-security.version}</version>
</dependency>
<!-- Spring Mail -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>${spring-mail.version}</version>
</dependency>
<!-- Spring Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${spring-data-redis.version}</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<!-- PDFBox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>${pdfbox.version}</version>
</dependency>
<!-- LangChain4j (AI) -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<!-- Fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>${nacos.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>${nacos.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
⑤统一编译工具和打包工具的版本及配置标准,一劳永逸
XML
<!-- 5.统一编译工具和打包工具的版本及配置标准,一劳永逸-->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
2.将bom项目install(安装)到本地

3.在微服务项目中使用(以菜单服务menu-service为例)
注意:前提是两个项目必须使用同一个maven仓库,不然这不是纯扯淡吗,根本不可能找到。
XML
<!-- 1.导入BOM项目(不添加依赖,而是导入版本信息)-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.casually</groupId>
<artifactId>myproject_bom</artifactId>
<version>1.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- ----------------------------------------------- -->
<!-- 2.导入其他所需的依赖(但是不用声明版本了,因为1中已经规定好了)-->
<dependencies>
<!-- Web依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
好处:设置了BOM项目以后,微服务项目引入依赖时再也不用写版本号了,因为BOM已经事先规定好了
注意:不要把具体的依赖,放进<dependencyManagement>标签中,不然依赖只被声明,但并不会导入
四.这样做的好处
- 开发效率极高
创建新微服务时,你只需要复制一份标准的pom.xml模板,修改artifactId即可。所有依赖版本自动对齐,不需要去查单体项目用了什么版本。
- 版本一致性(防冲突)
所有微服务(用户服务、订单服务、菜单服务)都强制使用同一套依赖版本。彻底杜绝了"服务A用Jackson 2.11,服务B用Jackson 2.13"导致的序列化报错。
- 一键升级
如果Spring Boot出了安全漏洞需要升级,你只需要修改myproject-bom里的 $ {spring-boot.version}变量,然后重新发布BOM。所有微服务只需要更新父版本号,即可全部完成升级。
针对你当前情况的建议
既然你已经有了单体项目,想拆分微服务,建议按以下路径操作:
提取
打开你单体项目的pom.xml,把里面用到的所有
<version>提取出来,放到一个新的myproject-bom工程的<properties>中。发布
执行mvn install,把这个myproject-bom安装到你本地的Maven仓库(或者公司的Nexus/Artifactory私服)。
新建
创建menu-service,在pom.xml中
<parent>指向myproject-bom(或者继承它的父工程)。清洗
在menu-service的pom.xml中,大胆删除所有依赖的
<version>标签。这样,你就从"手工管理依赖"进化到了"工程化管理依赖"。