一、Maven多模块项目基础概念
1.1 什么是Maven多模块项目
Maven多模块项目是通过一个父项目(parent project)管理多个子模块(submodule)的项目结构。就像一家公司有多个部门(财务部、技术部、市场部)一样,每个部门各司其职但都属于同一家公司。
优势对比表:
|
单模块项目 |
多模块项目 |
|
所有代码在一个工程中 |
按功能/层次拆分为多个模块 |
|
构建时间长 |
只构建修改的模块,效率高 |
|
依赖管理混乱 |
统一父POM管理依赖,版本一致 |
|
适合小型项目 |
适合中大型复杂项目 |
1.2 核心概念图解
依赖
依赖
依赖
Parent Project
Common Module
Service Module
Web Module
第三方库
二、项目初始化与基础搭建
2.1 创建父工程
- 使用Spring Initializr或IDE创建父项目
- 修改pom.xml,关键配置如下:
<!-- 父工程pom.xml -->
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>multi-module-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging> <!-- 关键!父项目必须是pom类型 -->
<modules>
<module>common</module>
<module>service</module>
<module>web</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
</project>
2.2 创建子模块
步骤说明:
- 在父项目目录下创建子模块文件夹
- 在每个子模块中创建自己的pom.xml
- 子模块继承父项目的配置
<!-- common模块pom.xml -->
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>multi-module-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>common</artifactId>
<packaging>jar</packaging>
<dependencies>
<!-- 公共依赖 -->
</dependencies>
</project>
三、模块依赖与接口设计
3.1 模块间依赖关系
Web
Service
Common
Database
3.2 接口定义示例(Common模块)
/**
* 通用响应封装类
* @param <T> 响应数据类型
*
* 使用场景:所有模块的API统一响应格式
* 设计思路:借鉴信封概念,包含状态码、消息和数据三部分
*/
public class CommonResponse<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 状态码(200=成功,500=系统错误...)
* 示例:200
*/
private int code;
/**
* 提示信息
* 示例:"操作成功"
*/
private String message;
/**
* 实际返回数据
* 示例:用户信息对象
*/
private T data;
// 构造方法、getter/setter省略...
}
3.3 Service模块接口示例
/**
* 用户服务接口
*
* 功能说明:提供用户相关的业务逻辑处理
* 调用流程:
* 1. Controller接收请求
* 2. 调用Service接口
* 3. Service处理业务逻辑
* 4. 返回处理结果
*/
public interface UserService {
/**
* 根据ID查询用户
* @param userId 用户ID
* @return 用户信息
* @throws BusinessException 当用户不存在时抛出
*
* 使用场景:用户信息查询页面
* 参数说明:
* - userId: 必须大于0
*/
UserDTO getUserById(Long userId) throws BusinessException;
/**
* 分页查询用户列表
* @param pageReq 分页请求参数
* @return 分页结果
*
* 示例:
* {
* "pageNum": 1,
* "pageSize": 10,
* "name": "张"
* }
*/
PageResult<UserDTO> listUsers(PageRequest pageReq);
}
四、高级配置与优化
4.1 依赖管理最佳实践
父POM中的dependencyManagement:
<!-- 父pom.xml中 -->
<dependencyManagement>
<dependencies>
<!-- 统一管理依赖版本 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<!-- 模块间依赖版本管理 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
子模块引用依赖时无需指定版本:
<!-- service模块pom.xml -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
</dependency>
</dependencies>
4.2 多环境配置
application.yml
application-dev.yml
application-test.yml
application-prod.yml
配置示例:
# application.yml
spring:
profiles:
active: @activatedProperties@ # Maven过滤替换
# application-dev.yml
server:
port: 8080
datasource:
url: jdbc:mysql://localhost:3306/dev_db
Maven profile配置:
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<activatedProperties>dev</activatedProperties>
</properties>
</profile>
</profiles>
五、实战案例:用户注册流程
5.1 代码结构
src/
├── main/
│ ├── java/
│ │ ├── com.example.web/
│ │ │ ├── UserController.java
│ │ ├── com.example.service/
│ │ │ ├── impl/
│ │ │ │ ├── UserServiceImpl.java
│ │ ├── com.example.common/
│ │ │ ├── exception/
│ │ │ │ ├── BusinessException.java
├── resources/
│ ├── application.yml
5.2 完整代码示例
Controller层:
/**
* 用户控制器
*
* 功能:处理用户相关的HTTP请求
* 调用流程:
* 1. 接收HTTP请求
* 2. 参数校验
* 3. 调用Service层
* 4. 返回统一格式响应
*/
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
/**
* 用户注册接口
* @param registerReq 注册请求体
* @return 注册结果
*
* 示例请求:
* POST /api/users/register
* {
* "username": "testuser",
* "password": "Test@123",
* "email": "test@example.com"
* }
*/
@PostMapping("/register")
public CommonResponse<Long> register(@Valid @RequestBody UserRegisterReq registerReq) {
try {
Long userId = userService.register(registerReq);
return CommonResponse.success(userId);
} catch (BusinessException e) {
return CommonResponse.fail(e.getCode(), e.getMessage());
}
}
}
Service实现层:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public Long register(UserRegisterReq registerReq) throws BusinessException {
// 1. 检查用户名是否已存在
if (userRepository.existsByUsername(registerReq.getUsername())) {
throw new BusinessException(ErrorCode.USERNAME_EXISTS);
}
// 2. 密码加密
String encryptedPwd = PasswordUtil.encrypt(registerReq.getPassword());
// 3. 构建用户实体
User user = new User();
user.setUsername(registerReq.getUsername());
user.setPassword(encryptedPwd);
user.setEmail(registerReq.getEmail());
user.setCreateTime(LocalDateTime.now());
// 4. 保存用户
User savedUser = userRepository.save(user);
return savedUser.getId();
}
}
六、进阶主题:自定义Starter开发
6.1 为什么要自定义Starter
就像家电的”即插即用”功能,自定义Starter可以让特定功能被其他项目轻松引入和使用。
典型场景:
- 公司内部通用组件封装
- 特定技术集成(如Redis锁、分布式ID生成器等)
- 第三方服务SDK封装
6.2 创建自定义Starter步骤
- 创建autoconfigure模块
- 创建starter模块(空模块,只依赖autoconfigure)
- 编写自动配置类
@Configuration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyProperties properties) {
return new MyService(properties);
}
}
- 在META-INF/spring.factories中注册自动配置类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.example.mystarter.autoconfigure.MyAutoConfiguration
七、常见问题解决方案
7.1 循环依赖问题
问题表现:
The dependencies of some of the beans in the application context form a cycle
解决方案对比表:
|
解决方案 |
适用场景 |
优缺点 |
|
重构设计 |
设计初期 |
最佳方案,但改动大 |
|
@Lazy注解 |
紧急修复 |
快速解决但可能隐藏设计问题 |
|
接口分离 |
服务间依赖 |
推荐方案,符合SOLID原则 |
7.2 模块热部署配置
<!-- 父pom.xml中添加 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
IDEA设置:
- Settings → Build → Compiler → 勾选”Build project automatically”
- Ctrl+Shift+A → 搜索”Registry” → 勾选”compiler.automake.allow.when.app.running”
八、性能优化提议
8.1 构建优化
并行构建配置:
mvn -T 1C clean install # 使用1核CPU per module
跳过测试:
mvn -DskipTests=true clean install
8.2 依赖树分析
mvn dependency:tree -Dverbose -Dincludes=org.springframework
输出示例:
[INFO] com.example:web:jar:1.0.0
[INFO] +- com.example:service:jar:1.0.0:compile
[INFO] | - com.example:common:jar:1.0.0:compile
[INFO] - org.springframework.boot:spring-boot-starter-web:jar:2.7.0:compile
九、总结与最佳实践
- 模块划分原则:
- 按功能划分(用户、订单、支付)
- 按架构层次划分(web、service、repository)
- 按复用性划分(common、utils)
- 版本管理策略:
- 父POM统一管理依赖版本
- 使用properties聚焦定义版本号
- 子模块继承父版本
- 接口设计提议:
- 模块间通过接口通信
- 定义清晰的DTO对象
- 统一异常处理机制
30%25%25%20%多模块项目开发时间分布设计规划接口定义集成测试模块拆分
通过本文的详细讲解,您应该已经掌握了Spring Boot与Maven多模块项目整合的全套技能。记住,好的项目结构就像精心设计的城市布局,能让后续的开发维护工作事半功倍。
关注我?别别别,我怕你笑出腹肌找我赔钱。
头条对markdown的文章显示不太友善,想了解更多的可以关注微信公众号:“Eric的技术杂货库”,有更多的干货以及资料下载。





















- 最新
- 最热
只看作者