当前位置: 代码网 > it编程>编程语言>Java > SpringBoot多模块依赖冲突排查与架构优化实战

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

2026年04月29日 Java 我要评论
前言:在springboot多模块项目开发中,依赖冲突、版本不一致、模块依赖设计不合理是最常见的“拦路虎”。本文结合实际项目场景,记录从依赖版本冲突(tomcat、spring

前言:在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多模块依赖冲突排查与优化的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com