告别“复制粘贴”!微服务架构下如何统一管理POM依赖版本(实战详解)

一.先说一个场景?

很多从单体应用转型微服务的同学都会遇到这样一个尴尬的场景:

刚开始拆分单体项目时,每新建一个微服务(比如把单体项目的菜单功能单独拆成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>标签。

这样,你就从"手工管理依赖"进化到了"工程化管理依赖"。

相关推荐
AI服务老曹2 小时前
从GB28181接入到边缘NPU算力调度:深度解析支持异构计算的工业级AI视频管理平台架构
人工智能·架构·音视频
齐潇宇2 小时前
Kubectl命令指南
linux·运维·云原生·容器·kubernetes
互联科技报2 小时前
短视频矩阵混剪工具源码架构深度解析:从超级编导、筷子科技到超级智剪2.0的技术范式演进
科技·矩阵·架构
AI服务老曹2 小时前
【架构深度解析】从异构计算到微服务:构建支持 X86/ARM 与 GPU/NPU 协同的 GB28181 视频 AI 平台
arm开发·微服务·架构
前端不太难2 小时前
鸿蒙游戏架构进阶:如何拆分 Store 与 System?
游戏·架构·harmonyos
ai产品老杨2 小时前
【架构解析】高并发 AI 视频流管理平台:实现 X86/ARM 异构部署与 GB28181 全链路源码交付
arm开发·人工智能·架构
User_芊芊君子2 小时前
数据库选型指南:架构演进的技术实践
大数据·数据库·架构
立莹Sir4 小时前
商品中台架构设计与技术落地实践——基于Spring Cloud微服务体系的完整解决方案
分布式·后端·spring cloud·docker·容器·架构·kubernetes