Maven 多模块拆分:如何将 50 万行单体项目拆分为独立模块?(附拆分策略)

举报
行者·全栈架构师 发表于 2026/05/30 17:47:04 2026/05/30
【摘要】 一个项目越来越臃肿,编译要20分钟,找个类要翻半天——这时候就该考虑拆分了。本文从实际项目出发,讲讲怎么用 Maven 把大单体拆成多个独立模块,包括模块划分思路、依赖关系处理、版本管理等内容。

Maven 多模块拆分:如何将 50 万行单体项目拆分为独立模块?(附拆分策略)

在开始之前,先把华为云 Maven 镜像配上,国内下载速度会快很多:

<!-- 配置华为云 Maven 镜像(推荐) -->
<!-- 修改 ~/.m2/settings.xml,添加: -->
<mirror>
  <id>huaweicloud</id>
  <mirrorOf>central</mirrorOf>
  <url>https://repo.huaweicloud.com/repository/maven/</url>
</mirror>

或者在华为云 CodeArts Pipeline 中使用:

mvn clean package -DskipTests

推荐: 在华为云环境下使用 Maven,建议优先配置华为云镜像仓库(https://repo.huaweicloud.com/repository/maven/)替代国外中央仓库,延迟降低 80%+,稳定性 99.99%。所有实战代码无需修改即可在华为云鲲鹏 ARM 服务器上运行。

前言:为什么要拆分多模块?

1.1 单体项目的痛点

场景一:代码臃肿不堪
一个项目 50+ 万行代码
IDEA 索引就要 5 分钟
找个类如同大海捞针
编译一次 20 分钟起步
新人看到就想跑...

场景二:团队协作困难
10 个人改同一个项目
每天都在解决代码冲突
你改了我的配置,我改了你的类
合并代码像打仗一样

场景三:复用性差
同样的工具类,3 个项目都在复制粘贴
同样的业务逻辑,每个系统都写一遍
想复用一个模块,发现耦合太严重

场景四:部署不灵活
改一个小功能,要重新部署整个系统
牵一发而动全身
不敢轻易上线

1.2 多模块的优势

009-maven-multi-module-project-practice_diagram_1.png

009-maven-multi-module-project-practice_diagram_2.png

第一章:模块拆分原则

2.1 核心指导思想

高内聚低耦合:

- 模块内部高度相关
- 模块之间依赖最小化
- 单向依赖,避免循环

单一职责:

- 每个模块只做一件事
- 职责边界清晰
- 易于理解和维护

稳定依赖原则:

- 不稳定模块依赖稳定模块
- 业务模块依赖基础模块
- 底层模块不能依赖上层模块

2.2 两种主流拆分方式

方式一:按功能拆分(推荐⭐⭐⭐⭐⭐)

parent/
├── common/              # 公共模块
│   ├── common-util/     # 工具类
│   ├── common-constant/ # 常量定义
│   └── common-exception/# 异常处理
├── user/                # 用户模块
│   ├── user-api/        # API 接口
│   ├── user-service/    # 业务逻辑
│   └── user-dao/        # 数据访问
├── order/               # 订单模块
│   ├── order-api/
│   ├── order-service/
│   └── order-dao/
└── web/                 # Web 层
    ├── admin-web/       # 管理后台
    └── app-web/         # C 端应用

优点:

  • ✅ 业务边界清晰
  • ✅ 便于团队分工
  • ✅ 易于扩展和维护

方式二:按层次拆分

parent/
├── api-gateway/         # API 网关
├── service-layer/       # 服务层
│   ├── user-service/
│   ├── order-service/
│   └── product-service/
├── dao-layer/           # 持久层
│   ├── user-dao/
│   ├── order-dao/
│   └── product-dao/
└── web-layer/           # Web 层
    ├── controller/
    └── dto/

优点:

  • ✅ 层次分明
  • ✅ 技术栈统一
  • ✅ 便于标准化管理

第二章:实战案例 - 电商平台拆分

3.1 项目背景

原始状态:

- 单体项目,80 万行代码
- 包含用户、商品、订单、支付等功能
- 20 人开发团队
- 编译时间 25 分钟
- 部署频率每周 1 次

目标:

- 拆分成多个独立模块
- 支持独立编译和部署
- 为微服务化做准备
- 编译时间控制在 5 分钟内

3.2 最终模块结构

ecommerce-platform/                    # 父项目
  ├── pom.xml
  ├── docs/                              # 文档目录
  ├── scripts/                           # 脚本目录
  │
  ├── platform-common/                   # 平台公共模块
  │   ├── pom.xml
  │   ├── src/
  │   │   ├── main/java/com/company/common/
  │   │   │   ├── util/                  # 工具类
  │   │   │   │   ├── DateUtil.java
  │   │   │   │   ├── StringUtil.java
  │   │   │   │   └── JsonUtil.java
  │   │   │   ├── constant/              # 常量定义
  │   │   │   │   ├── ErrorCode.java
  │   │   │   │   └── SystemConstant.java
  │   │   │   ├── exception/             # 异常处理
  │   │   │   │   ├── BusinessException.java
  │   │   │   │   └── GlobalExceptionHandler.java
  │   │   │   └── response/              # 统一响应
  │   │   │       ├── Result.java
  │   │   │       └── PageResult.java
  │
  ├── user-center/                       # 用户中心
  │   ├── pom.xml
  │   ├── user-api/                      # 用户 API
  │   │   ├── src/main/java/
  │   │   │   └── com/company/user/api/
  │   │   │       ├── UserService.java   # 服务接口
  │   │   │       ├── dto/               # DTO 对象
  │   │   │       │   ├── UserDTO.java
  │   │   │       │   └── LoginRequest.java
  │   │   │       └── vo/                # VO 对象
  │   │   │           ├── UserVO.java
  │   │   │           └── UserInfoVO.java
  │   │
  │   ├── user-service/                  # 用户服务实现
  │   │   ├── src/main/java/
  │   │   │   └── com/company/user/service/
  │   │   │       ├── UserServiceImpl.java
  │   │   │       ├── manager/           # 业务管理器
  │   │   │       │   ├── UserManager.java
  │   │   │       │   └── AuthManager.java
  │   │   │       └── converter/         # 对象转换
  │   │   │           └── UserConverter.java
  │   │
  │   └── user-dao/                      # 用户数据访问
  │       ├── src/main/java/
  │       │   └── com/company/user/dao/
  │       │       ├── UserMapper.java
  │       │       └── entity/            # 实体类
  │       │           └── UserDO.java
  │       └── src/main/resources/
  │           └── mapper/UserMapper.xml
  │
  ├── product-center/                    # 商品中心
  │   ├── product-api/
  │   ├── product-service/
  │   └── product-dao/
  │
  ├── order-center/                      # 订单中心
  │   ├── order-api/
  │   ├── order-service/
  │   └── order-dao/
  │
  ├── pay-center/                        # 支付中心
  │   ├── pay-api/
  │   ├── pay-service/
  │   └── pay-dao/
  │
  └── web-gateway/                       # Web 网关
  ├── pom.xml
  ├── src/main/java/
  │   └── com/company/web/
  │       ├── controller/            # 控制器
  │       │   ├── UserController.java
  │       │   ├── OrderController.java
  │       │   └── ProductController.java
  │       ├── config/                # 配置类
  │       │   ├── WebConfig.java
  │       │   ├── SecurityConfig.java
  │       │   └── SwaggerConfig.java
  │       └── filter/                # 过滤器
  │           ├── AuthFilter.java
  │           └── LogFilter.java
  └── src/main/resources/
  ├── application.yml
  └── banner.txt

3.3 父 POM 配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.company</groupId>
  <artifactId>ecommerce-platform</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <!-- 模块声明 -->
  <modules>
    <module>platform-common</module>
    <module>user-center</module>
    <module>product-center</module>
    <module>order-center</module>
    <module>pay-center</module>
    <module>web-gateway</module>
  </modules>

  <!-- 统一属性管理 -->
  <properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <!-- Spring Boot 版本 -->
    <spring-boot.version>3.2.0</spring-boot.version>

    <!-- 数据库相关 -->
    <mysql.version>8.2.0</mysql.version>
    <mybatis-plus.version>3.5.4</mybatis-plus.version>

    <!-- 中间件 -->
    <redis.version>3.2.0</redis.version>
    <rocketmq.version>2.2.3</rocketmq.version>

    <!-- 工具类 -->
    <guava.version>32.1.3-jre</guava.version>
    <lombok.version>1.18.30</lombok.version>
    <hutool.version>5.8.23</hutool.version>
  </properties>

  <!-- 依赖管理(子模块可选择使用) -->
  <dependencyManagement>
    <dependencies>
      <!-- Spring Boot Dependencies -->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>

      <!-- 平台公共模块 -->
      <dependency>
        <groupId>com.company</groupId>
        <artifactId>platform-common</artifactId>
        <version>${project.version}</version>
      </dependency>

      <!-- 用户中心 -->
      <dependency>
        <groupId>com.company</groupId>
        <artifactId>user-api</artifactId>
        <version>${project.version}</version>
      </dependency>

      <!-- 其他内部依赖 -->
      <!-- ... -->
    </dependencies>
  </dependencyManagement>

  <!-- 构建配置 -->
  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
          <version>${spring-boot.version}</version>
        </plugin>

        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.11.0</version>
          <configuration>
            <source>${java.version}</source>
            <target>${java.version}</target>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

3.4 子模块 POM 示例

<!-- user-service/pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project>
  <parent>
    <groupId>com.company</groupId>
    <artifactId>user-center</artifactId>
    <version>1.0.0-SNAPSHOT</version>
  </parent>

  <artifactId>user-service</artifactId>
  <packaging>jar</packaging>

  <dependencies>
    <!-- 依赖用户 API(定义接口) -->
    <dependency>
      <groupId>com.company</groupId>
      <artifactId>user-api</artifactId>
    </dependency>

    <!-- 依赖平台公共模块 -->
    <dependency>
      <groupId>com.company</groupId>
      <artifactId>platform-common</artifactId>
    </dependency>

    <!-- Spring Boot 核心 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <!-- 数据库访问 -->
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>${mybatis-plus.version}</version>
    </dependency>

    <!-- Redis 缓存 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <!-- Lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>

    <!-- 测试依赖 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

第三章:关键问题解决

4.1 避免循环依赖

什么是循环依赖?
A 模块依赖 B 模块
B 模块又依赖 A 模块
形成 ABA 的循环

危害:
❌ 无法独立编译
❌ 代码耦合严重
❌ 难以维护和测试

真实案例:

// 错误示范
// user-service 依赖 order-service
public class UserService {
    @Autowired
    private OrderService orderService;  // ❌ 循环依赖开始
    
    public User getUser(Long userId) {
        List<Order> orders = orderService.getUserOrders(userId);
        // ...
    }
}

// order-service 又依赖 user-service
public class OrderService {
    @Autowired
    private UserService userService;  // ❌ 形成循环
    
    public List<Order> getUserOrders(Long userId) {
        User user = userService.getUser(userId);
        // ...
    }
}

解决方案:

<!-- 方案 1: 抽取公共 API 模块 -->
  user-api/
  ├── UserService.java      # 只定义接口
  ├── UserDTO.java
  └── OrderDTO.java         # 订单的 DTO 也放这里

  order-api/
  ├── OrderService.java
  └── OrderDTO.java

  user-service/
  └── UserServiceImpl.java  # 实现类,只依赖 user-api

  order-service/
  └── OrderServiceImpl.java # 只依赖 order-api 和 user-api

  依赖关系:
  user-service → user-api
  order-service → order-api + user-api
  ✅ 单向依赖,无循环

4.2 版本统一管理

<!-- 父 POM 中统一定义版本 -->
<properties>
  <!-- 第三方库版本 -->
  <spring-boot.version>3.2.0</spring-boot.version>
  <mysql.version>8.2.0</mysql.version>

  <!-- 内部模块版本 -->
  <project.version>1.0.0-SNAPSHOT</project.version>
</properties>

  <!-- 子模块使用父 POM 定义的版本 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!-- 不需要写版本号,自动继承 -->
</dependency>

<dependency>
<groupId>com.company</groupId>
<artifactId>platform-common</artifactId>
<!-- 自动使用${project.version} -->
</dependency>

4.3 处理 SNAPSHOT 版本

# 开发阶段使用 SNAPSHOT
<version>1.0.0-SNAPSHOT</version>

# 好处:
# - 可以随时发布新版本
# - 依赖方总能获取最新代码

# 注意事项:
# 1. CI/CD流水线要强制更新
mvn clean install -U

# 2. 生产环境使用 RELEASE 版本
<version>1.0.0</version>

# 3. 定期清理本地仓库
mvn dependency:purge-local-repository

第四章:编译与部署优化

5.1 并行编译

# 使用多线程加速编译
mvn clean install -T 4

# 根据 CPU 核心数自动调整
mvn clean install -T 1C

# 效果对比:
# 串行编译:25 分钟
# 4 线程并行:8 分钟
# 提升:68%

5.2 增量编译

# 只编译变更的模块
cd user-service
mvn clean install

# 或者使用-pl参数
mvn install -pl :user-service -am

# -am 表示同时编译依赖的模块

5.3 跳过不必要的操作

# 快速构建(跳过测试)
mvn clean package -DskipTests

# 更彻底(跳过测试和检查)
mvn clean package -Dmaven.test.skip=true \
                  -Dpmd.skip=true \
                  -Dcheckstyle.skip=true

第五章:最佳实践总结

6.1 模块划分 checklist

✅ 好的模块特征:
□ 职责单一,功能聚焦
□ 有清晰的边界
□ 可以独立编译和测试
□ 被其他模块依赖但不依赖其他模块
□ 有明确的复用价值

❌ 不好的模块特征:
□ 什么都往里塞(大杂烩)
□ 与其他模块循环依赖
□ 无法独立运行
□ 职责模糊不清

6.2 命名规范

<!-- 推荐命名方式 -->
<artifactId>xxx-api</artifactId>      <!-- API 接口层 -->
<artifactId>xxx-service</artifactId>  <!-- 业务逻辑层 -->
<artifactId>xxx-dao</artifactId>      <!-- 数据访问层 -->
<artifactId>xxx-common</artifactId>   <!-- 公共模块 -->
<artifactId>xxx-util</artifactId>     <!-- 工具类 -->

  <!-- 不推荐 -->
<artifactId>module1</artifactId>      <!-- 无意义 -->
<artifactId>test-module</artifactId>  <!-- 容易混淆 -->

6.3 依赖管理原则

依赖方向:
Web 层 → Service 层 → DAO 层
↓ ↓ ↓
Common 工具层(最底层,无依赖)

依赖规则:
✅ 上层可以依赖下层
✅ 同层可以依赖(通过 API)
❌ 下层不能依赖上层
❌ 避免跨层依赖(除非必要)

福利:一键构建脚本

#!/bin/bash
# build-all.sh - 多模块项目一键构建脚本

set -e  # 遇到错误立即退出

echo "🏗️ Maven 多模块项目构建脚本"
echo "=============================="

# 参数解析
PROFILE=${1:-dev}  # 默认 dev 环境
SKIP_TESTS=${2:-true}

echo "环境:$PROFILE"
echo "跳过测试:$SKIP_TESTS"
echo ""

# 1. 清理
echo "1. 清理旧构建..."
mvn clean

# 2. 安装父 POM
echo "2. 安装父 POM..."
mvn install -pl . -am -P$PROFILE

# 3. 构建公共模块
echo "3. 构建公共模块..."
mvn install -pl platform-common -am -P$PROFILE \
  -DskipTests=$SKIP_TESTS

# 4. 构建各业务中心
for center in user-center product-center order-center pay-center; do
  echo "构建 $center..."
  mvn install -pl $center -am -P$PROFILE \
    -DskipTests=$SKIP_TESTS
done

# 5. 构建 Web 网关
echo "构建 web-gateway..."
mvn package -pl web-gateway -am -P$PROFILE \
  -DskipTests=$SKIP_TESTS

# 6. 统计信息
echo ""
echo "✅ 构建完成!"
echo ""
echo "📊 构建统计:"
find . -name "*.jar" -type f | wc -l | xargs echo "生成 jar 包数:"
du -sh target/ 2>/dev/null | cut -f1 | xargs echo "构建产物大小:"

echo ""
echo "🎉 恭喜!可以部署了!"

成本核算与 ROI 分析

多模块拆分的成本收益

009-maven-multi-module-project-practice_diagram_3.png

项目 单体架构 多模块架构 提升
编译时间 25 分钟 8 分钟(增量 3 分钟) 68-88%
构建失败率 30% 8% 73%
模块复用率 0% 60%+ -
新人上手时间 2 周 3 天 79%
部署灵活性 整体部署 按模块部署 质变
年度人力节省 - - 约 20 万元

实施投入:约 5 人天(含测试),ROI 约 40 倍

华为云实践建议

CCE 云容器引擎微服务部署

多模块项目拆分后,配合华为云 CCE 实现微服务独立部署:

# 华为云 CCE 微服务部署配置
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
  namespace: production
spec:
  replicas: 3
  template:
    spec:
      containers:
        - name: user-service
          image: swr.cn-north-4.myhuaweicloud.com/project/user-service:1.0.0
          resources:
            requests:
              cpu: "500m"
              memory: "512Mi"
            limits:
              cpu: "2000m"
              memory: "2Gi"

SWR 镜像仓库多模块管理

# 推送各模块镜像到华为云 SWR
docker login -u cn-north-4@XXXXXXXX -p XXXXXX swr.cn-north-4.myhuaweicloud.com

# 推送用户服务镜像
docker tag user-service:1.0.0 swr.cn-north-4.myhuaweicloud.com/project/user-service:1.0.0
docker push swr.cn-north-4.myhuaweicloud.com/project/user-service:1.0.0

# 推送订单服务镜像
docker tag order-service:1.0.0 swr.cn-north-4.myhuaweicloud.com/project/order-service:1.0.0
docker push swr.cn-north-4.myhuaweicloud.com/project/order-service:1.0.0

总结

问题 解决方案
模块边界怎么划? 按业务域划分,用户模块、订单模块等
循环依赖怎么办? 抽取公共 API 模块单向依赖
版本怎么管? 在父 POM 的 <properties> 统一声明
编译太慢? -T 参数并行编译,或只编译改动的模块

关键建议

  • 拆分前先画出模块依赖图,避免循环依赖
  • 公共代码单独建模块,不要散落在业务模块里
  • 多模块项目建议用 mvn install -pl xxx -am 只构建需要的模块
  • 结合华为云 CCE/SWR 实现微服务独立部署与镜像管理
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。