导读:本期聚焦于香港程序员创作的《SpringBoot项目中如何搭建Maven多模块父子工程?详细步骤、优势与适用场景一次讲清》,敬请观看详情。在单体工程逐渐膨胀后,包结构会变得难以维护,构建速度也会同步下降。Maven多模块父子工程的核心思路,是让一个聚合POM统一管理依赖版本与插件配置,再由若干子模块各自负责独立边界,最后通过模块依赖完成组装。本文从SpringBoot项目的实际拆分需求出发,先说明父工程、子模块、聚合与继承的关系,再给出从空目录创建父POM、配置SpringBoot依赖管理、建立common、service、web等模块的详细步骤,包括模块间如何引用以及启动类如何扫描组件。文章还会对比单模块与多模块在构建、测试、部署上的差异,梳理接口层与实现层分离、公共工具模块复用、多人协作等适用场景,并指出包名冲突、依赖循环、版本漂移等常见问题及规避方法。

SpringBoot项目在初期用单个工程就能快速启动,但业务模块增多后,包目录会越来越深,公共工具类散落各处,一次全量构建也可能拖慢开发节奏。Maven多模块父子工程正是针对这类膨胀问题的结构优化方案:用父工程统一管理依赖版本和插件,用子模块划分职责边界,再通过模块依赖完成组装。本文会从工程结构、创建步骤、优势场景和避坑要点几个方面展开。

SpringBoot项目中如何搭建Maven多模块父子工程?详细步骤、优势与适用场景一次讲清

一、先理解聚合与继承:多模块工程的核心机制

Maven多模块父子工程并不是一个单独的新项目类型,而是Maven聚合(aggregation)与继承(inheritance)两种能力组合后的工程组织方式。聚合强调一个父工程可以同时管理多个子模块,父工程的<packaging>必须设置为pom,并在<modules>中声明所有子模块。Maven执行mvn install时会按照依赖关系构建整个模块集合。

继承则解决版本管理问题。子模块通过<parent>指向父工程后,可以继承父工程中定义的<dependencyManagement>和<pluginManagement>。子模块引入依赖时不用重复写版本号,版本提升或降级只需要改父工程一处。SpringBoot官方提供的spring-boot-starter-parent本质上就是一个父POM,项目里如果已经有自己的父工程,可以在父工程的<dependencyManagement>中导入spring-boot-dependencies,同样能达到统一管理SpringBoot依赖版本的效果。

常见的模块划分方式是:parent负责版本与聚合,common存放工具类、异常、常量、DTO等公共代码,service负责业务逻辑,web只负责接口暴露和请求参数处理。依赖方向保持web依赖service,service依赖common,不要反向引用。这样的单向依赖可以让模块边界清晰,也能减少循环依赖风险。

二、从零创建SpringBoot多模块父子工程

下面以一个demo-parent工程为例,创建common、service、web三个子模块。先建一个空目录,再创建父工程的pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.demo</groupId>
    <artifactId>demo-parent</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>

    <modules>
        <module>common</module>
        <module>service</module>
        <module>web</module>
    </modules>

    <properties>
        <java.version>17</java.version>
        <spring-boot.version>3.2.5</spring-boot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

接着创建common模块,目录为common,并新建它的pom.xml。该模块的parent指向demo-parent,通常只需要引入spring-boot-starter以获取基础能力,如果只是纯工具模块,也可以不引入Spring依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.demo</groupId>
        <artifactId>demo-parent</artifactId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>common</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
</project>

service模块需要依赖common,这样它可以复用工具类和公共DTO。业务接口可以定义在service模块,也可以拆成api和impl两个模块,这里先保持简单。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.demo</groupId>
        <artifactId>demo-parent</artifactId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>service</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.demo</groupId>
            <artifactId>common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
</project>

web模块是最终可运行模块,它需要依赖service,并引入spring-boot-starter-web。启动类放在com.demo.web包下,同时配置组件扫描范围覆盖com.demo,这样才能加载到service和common中的Spring组件。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.demo</groupId>
        <artifactId>demo-parent</artifactId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>web</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.demo</groupId>
            <artifactId>service</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

启动类的示例代码如下:

package com.demo.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = {"com.demo"})
public class WebApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }
}

整个工程的目录结构可以规划为下面这样,所有子模块都在父工程目录下,pom文件与src目录分离:

demo-parent
    pom.xml
    common/pom.xml
    common/src/main/java/com/demo/common
    service/pom.xml
    service/src/main/java/com/demo/service
    web/pom.xml
    web/src/main/java/com/demo/web

三、多模块父子工程带来的实际优势

版本管理集中是最直接的好处。单体项目里如果每个模块都各自写依赖版本,升级SpringBoot时需要全局搜索替换,容易漏改。多模块工程把spring-boot-dependencies或spring-boot-starter-parent放在父POM中,子模块只声明groupId和artifactId,版本冲突概率大幅降低。遇到需要统一升级安全补丁时,通常只改父POM一处即可。

第二个优势是构建和复用边界更清晰。公共模块可以单独打成jar供其他系统使用,职责边界也通过目录和依赖关系固定下来。比如common模块不应该依赖业务模块,如果误引入,Maven构建时会因为找不到依赖而提前暴露问题。团队协作时,每个人负责不同模块,代码冲突范围更小。

此外,多模块结构对日后向微服务演进也比较友好。虽然多模块不等于微服务,但清晰的模块边界会让拆分服务时工作量更小。CI/CD流水线可以按模块选择构建任务,不必每次提交都全量编译,开发期反馈速度会更快。

四、适用场景与常见避坑点

并不是所有项目都适合一开始就拆多模块。如果一个内部管理系统只有两三个接口,或者项目体量很小,多模块反而增加目录层级和POM维护成本。通常当项目出现明显的公共代码沉淀、多人并行开发、多个可复用组件,或者计划拆分服务时,再切换到多模块结构收益更高。

实际搭建时有几个坑要避开。第一,父工程的<packaging>必须是pom,否则Maven不会把它当作聚合工程。第二,子模块的<relativePath>默认会向上找父POM,如果目录结构与标准Maven多模块不一致,需要显式指定相对路径。第三,模块之间要避免循环依赖,例如common依赖service,service又依赖common,Maven reactor构建时会报错。

SpringBoot启动类所在的包名也要格外注意。默认@SpringBootApplication只扫描启动类所在包及其子包,如果启动类在com.demo.web,而Service在com.demo.service,就必须通过@ComponentScan扩大扫描范围,或者把所有模块的根包统一为com.demo再放置启动类在根包下。最后,子模块依赖版本尽量使用${project.version}统一管理,而不是在各模块写死不同版本,否则会出现同一个父工程下版本漂移的问题。

SpringBootMaven多模块父子工程修改时间:2026-09-22 23:09:02

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0922/60661.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。