SpringBoot多模块依赖冲突排查与架构优化实战

 更新时间:2026年04月29日 09:16:09   作者:Mr.4567  
本文详细记录了在SpringBoot多模块项目开发中遇到的依赖版本冲突、模块依赖设计不合理等问题的排查和解决方案的过程,主要重点关注了父模块依赖管理、模块化拆分、按需依赖等等,需要的朋友可以参考下

前言:在SpringBoot多模块项目开发中,依赖冲突、版本不一致、模块依赖设计不合理是最常见的“拦路虎”。本文结合实际项目场景,记录从依赖版本冲突(tomcat、spring-security)到模块架构优化的完整排查、解决过程,总结企业级多模块最佳实践,帮助更多开发者避坑,提升项目可维护性。

本文核心解决场景:父模块+通用模块A+业务模块BCD的多模块结构中,依赖版本冲突、非公共依赖污染无关模块、模块依赖设计不合理等问题,全程贴合实际开发场景,提供可直接复用的解决方案。

一、项目初始结构(问题场景)

先明确项目初始结构,也是问题的起源,方便大家对号入座:

父项目(parent)
├── A模块(通用模块):包含service、dao、工具类,引入mybatis-plus、redis、spring-boot-starter-security等
├── B模块(业务模块):依赖A模块,需要security功能
├── C模块(业务模块):依赖A模块,不需要security功能
└── D模块(业务模块):依赖A模块,不需要security功能

初始问题汇总:

1. 父模块在dependencies中直接引入tomcat-embed-core、spring-boot-starter-web(带排除),导致子模块出现tomcat版本冲突(父模块10.1.54,A模块传递10.1.42);

2. A模块引入spring-boot-starter-security,需升级spring-security-web至6.5.10,但父模块锁定后不生效,A/B模块版本不一致;

3. A模块引入的security依赖,传递给不需要的C/D模块,造成依赖冗余;

4. 父模块未遵循“只管理版本,不引入依赖”的原则,导致依赖传递混乱。

二、核心问题排查与解决方案(按优先级)

以下解决方案按“先解决紧急冲突,再优化架构”的顺序,每一步都贴合实际操作,可直接复制配置使用。

问题1:tomcat-embed-core版本冲突(父模块10.1.54,子模块10.1.42)

1.1 问题根源

父模块在dependencies中直接引入tomcat-embed-core:10.1.54,同时父模块还引入了spring-boot-starter-web(排除了tomcat);A模块引入spring-boot-starter-web,自带tomcat-embed-core:10.1.42(SpringBoot 3.3.13默认版本);BCD模块依赖A模块,导致传递引入10.1.42,与父模块的10.1.54冲突。

关键原因:父模块直接在dependencies中引入依赖,优先级低于SpringBoot自带的版本管理;且未通过dependencyManagement统一锁定版本。

1.2 解决方案(父模块优化)

核心原则:父模块只通过dependencyManagement管理版本,不直接在dependencies中引入任何依赖。

<properties>
    <spring-boot.version>3.3.13</spring-boot.version>
    <tomcat.version>10.1.54</tomcat.version> <!-- 统一tomcat版本 -->
</properties>
<dependencyManagement>
    <dependencies>
        <!-- Spring Boot 官方依赖管理 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
<!-- 强制锁定tomcat版本,覆盖SpringBoot默认版本 -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>
<!-- 父模块dependencies标签为空,不引入任何依赖 -->
<dependencies>
</dependencies>

后续操作:删除父模块中所有直接引入的依赖(tomcat-embed-core、spring-boot-starter-web),A模块正常引入spring-boot-starter-web即可,无需排除tomcat,会自动继承父模块锁定的10.1.54版本。

问题2:spring-security-web版本升级不生效(需升级至6.5.10)

2.1 问题根源

A模块引入spring-boot-starter-security,父模块通过dependencyManagement锁定spring-security.version=6.5.10,但版本不生效,A/B模块仍显示6.3.10(SpringBoot 3.3.13默认版本)。

关键原因:spring-security-bom的导入顺序在spring-boot-dependencies之后,Maven规则“先导入的bom优先级更高”,导致SpringBoot自带的版本覆盖了我们锁定的版本。

2.2 解决方案(调整父模块bom导入顺序)

<properties>
    <spring-boot.version>3.3.13</spring-boot.version>
    <tomcat.version>10.1.54</tomcat.version>
    <spring-security.version>6.5.10</spring-security.version> <!-- 统一security版本 -->
</properties>
<dependencyManagement>
    <dependencies>
        <!-- 重点:spring-security-bom放前面,优先级高于SpringBoot自带版本 -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-bom</artifactId>
            <version>${spring-security.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- Spring Boot 官方依赖放后面 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- tomcat版本锁定 -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

验证方法:在A/B模块目录执行命令 mvn dependency:tree -Dincludes=org.springframework.security:spring-security-web,输出结果中版本为6.5.10即生效。

注意:无需在A模块做任何排除操作,保持spring-boot-starter-security的正常引入即可。

问题3:非公共依赖(security)污染无关模块(C/D)

3.1 问题根源

A模块作为通用模块,引入了只有B模块需要的spring-boot-starter-security,导致依赖A的C/D模块也被动引入了security,造成冗余和不必要的依赖污染。

关键原因:模块依赖设计不合理,将“非公共依赖”放入了通用模块A中。

3.2 解决方案(模块化拆分,按需依赖)

核心原则:通用模块A只放“所有子模块(BCD)都需要”的依赖,非公共依赖由需要的模块自己引入。

  1. 第一步:清理A模块,移除spring-boot-starter-security依赖(A模块只保留mybatis-plus、redis、dao、service等公共依赖);
  2. 第二步:B模块自己引入spring-boot-starter-security(因为只有B需要);
  3. 第三步:C/D模块只依赖A模块,不引入任何多余依赖。

具体配置:

<!-- A模块pom.xml(清理后) -->
<dependencies>
    <!-- 公共依赖:BCD都需要 -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- 其他公共service、dao相关依赖 -->
</dependencies>
<!-- B模块pom.xml(自己引入security) -->
<dependencies>
    <!-- 依赖通用模块A -->
    <dependency>
        <groupId>xxx</groupId>
        <artifactId>A</artifactId>
    </dependency>
    <!-- 自己需要的security,不传递给C/D -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies>
<!-- C/D模块pom.xml(只依赖A) -->
<dependencies>
    <dependency>
        <groupId>xxx</groupId>
        <artifactId>A</artifactId>
    </dependency>
</dependencies>

效果:B模块有security功能,C/D模块无security依赖,彻底解决依赖污染,无需任何排除操作。

三、最终优化后的标准架构(企业级最佳实践)

优化后结构,彻底解决所有问题,兼顾复用性和可维护性:

父项目(parent)
├── 核心职责:只通过dependencyManagement管理所有依赖版本,dependencies为空
├── A模块(core-service,通用模块)
│   ├── 核心职责:提供公共数据层、服务层能力,所有子模块都需要
│   ├── 依赖:mybatis-plus、redis、数据库驱动、公共entity/dao/service/工具类
│   └── 不包含:web、security等非公共依赖
├── B模块(业务模块)
│   ├── 依赖:A模块 + 自身需要的security等依赖
│   └── 核心职责:业务逻辑实现(需要security)
├── C模块(业务模块)
│   ├── 依赖:只依赖A模块
│   └── 核心职责:业务逻辑实现(不需要security)
└── D模块(业务模块)
    ├── 依赖:只依赖A模块
    └── 核心职责:业务逻辑实现(不需要security)

四、关键注意点(避坑核心)

结合本次排查,总结10个高频避坑点,覆盖依赖管理和模块设计:

  1. 父模块核心原则:只管理版本,不引入依赖,所有依赖通过dependencyManagement锁定,dependencies标签为空,避免子模块被动继承不必要的依赖;
  2. bom导入顺序:自定义版本的bom(如spring-security-bom)必须放在spring-boot-dependencies前面,否则会被SpringBoot默认版本覆盖;
  3. 通用模块A的定位:只放“所有子模块都需要”的依赖,非公共依赖(如security、web)绝对不放入;
  4. 版本统一:所有核心依赖(tomcat、security、mybatis-plus等)在父模块properties中定义变量,统一管理,避免硬编码;
  5. 依赖传递:子模块依赖通用模块时,会自动继承其所有依赖,因此通用模块必须“干净”,不引入非公共依赖;
  6. 避免排除滥用:排除(exclusion)只用于临时救急,长期解决方案是“按需依赖”,拆分模块,而非大量使用排除;
  7. 版本验证:修改依赖后,用mvn dependency:tree命令验证版本是否正确,避免隐性冲突;
  8. SpringBoot与组件版本兼容性:SpringBoot 3.3.13默认对应spring-security 6.3.x,升级至6.5.x需确认API兼容性(本次实践无问题);
  9. 模块命名规范:通用模块建议命名为core-service、common-core等,明确其定位,避免混淆;
  10. 长期维护:定期清理无用依赖,保持模块“瘦身”,避免依赖冗余导致的冲突和性能问题。

五、总结

SpringBoot多模块项目的核心痛点的是“依赖冲突”和“模块设计不合理”,本次实践通过“父模块版本统一管理+通用模块瘦身+按需依赖”,彻底解决了tomcat、spring-security版本冲突,以及非公共依赖污染问题。

核心思路:模块化设计的本质是“职责清晰、按需依赖”,父模块管版本,通用模块管公共能力,业务模块管自身需求,这样既能保证代码复用,又能避免依赖混乱,提升项目可维护性。

本文所有配置均经过实际项目验证,可直接复制使用,若遇到类似问题,可对照排查,也欢迎在评论区交流补充。

以上就是SpringBoot多模块依赖冲突排查与架构优化实战的详细内容,更多关于SpringBoot多模块依赖冲突排查与优化的资料请关注脚本之家其它相关文章!

相关文章

  • IDEA无法打开Marketplace的三种解决方案(推荐)

    IDEA无法打开Marketplace的三种解决方案(推荐)

    这篇文章主要介绍了IDEA无法打开Marketplace的三种解决方案(推荐),本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • Java前后端分离项目跨域问题解决方案

    Java前后端分离项目跨域问题解决方案

    本文主要介绍了Java前后端分离项目跨域问题解决方案,其中后端基于SpringBoot,前端使用了jQuery、axios等框架,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • SpringBoot异步实现 的8种方式

    SpringBoot异步实现 的8种方式

    在同步操作中,执行到 发送短信 的时候,我们必须等待这个方法彻底执行完才能执行 赠送积分 这个操作,如果 赠送积分 这个动作执行时间较长,发送短信需要等待,这就是典型的同步场景,这篇文章主要介绍了SpringBoot异步实现 的8种方式,需要的朋友可以参考下
    2023-11-11
  • 浅谈Java生命周期管理机制

    浅谈Java生命周期管理机制

    最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告诉你“怎样做”,但至于“为什么这样做”却不多说
    2016-01-01
  • fastjson生成json时Null属性不显示的解决方法

    fastjson生成json时Null属性不显示的解决方法

    下面小编就为大家带来一篇fastjson生成json时Null属性不显示的解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • 解决idea中maven项目无端显示404错误的方法

    解决idea中maven项目无端显示404错误的方法

    这篇文章主要介绍了解决idea中maven项目无端显示404错误的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • java实现在一张大图片上添加小图及文字

    java实现在一张大图片上添加小图及文字

    这篇文章主要介绍了java实现在一张大图上添加小图及文字,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java SPI的简单小实例

    Java SPI的简单小实例

    这篇文章主要介绍了Java SPI的简单小实例,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • Java中的接口知识汇总

    Java中的接口知识汇总

    本文给大家汇总介绍了在java中的接口知识,包括为什么要使用接口、什么是接口、抽象类和接口的区别、如何定义接口以及定义接口注意点,希望大家能够喜欢
    2016-04-04
  • 详解Java去除json数据中的null空值问题

    详解Java去除json数据中的null空值问题

    这篇文章主要介绍了详解Java去除json数据中的null空值问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08

最新评论