1. 模块化开发的重要性
在软件开发中,随着项目规模的不断扩大,模块化设计已成为提高代码可维护性和可复用性的关键实践。通过将大型项目拆分为多个独立模块,开发团队可以并行开发不同功能组件,降低代码耦合度,并提高整体开发效率。Spring Boot框架提供了良好的支持,使开发者能够轻松创建和管理多模块项目。
模块化开发允许每个模块专注于特定业务功能或技术层面,例如将数据访问层、业务逻辑层和Web层分离为独立模块。这种架构使得代码组织更加清晰,测试更加方便,并且有利于团队协作。
2. 创建父项目(Parent Project)
创建多模块项目首先需要建立一个父项目作为整个项目的基础容器。父项目不包含具体业务代码,而是负责统一管理所有子模块的依赖和配置。
2.1 初始化父项目
使用Spring Initializr
创建父项目,选择Maven作为构建工具,Java作为开发语言,并选择最新的Spring Boot稳定版本。创建完成后,需要修改父项目的pom.xml文件:
<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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>moduleA</module>
<module>moduleB</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
关键配置说明:
• packaging类型:必须设置为pom,表示这是一个父项目
• modules标签:包含所有子模块的列表
• parent标签:继承Spring Boot官方父项目,获得默认配置
2.2 清理父项目结构
由于父项目不包含实际代码,需要删除不必要的文件和文件夹:
• 删除.mvn文件夹和src目录
• 删除mvnw和mvnw.cmd文件
• 只保留pom.xml文件进行依赖管理
3. 新增子模块(Module)
3.1 创建子模块步骤
在父项目基础上新增子模块的流程如下:
在IDE中右键点击父项目,选择"New" → “Module”
选择Spring Initializr作为模块模板
设置子模块的GroupId和ArtifactId(不要与父项目重复)
选择所需的Spring Boot起步依赖
指定模块名称和存储路径
3.2 子模块pom.xml配置
每个子模块需要有独立的pom.xml文件,配置如下:
<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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>moduleA</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 其他模块依赖 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>common-module</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
子模块配置要点:
• parent配置:必须指向父项目
• packaging类型:通常设置为jar
• 依赖声明:添加模块特定需要的依赖
4. 模块间的依赖管理
4.1 统一依赖管理
在父项目中可以统一管理所有子模块的依赖版本,避免版本冲突:
<!-- 父项目pom.xml中 -->
<properties>
<java.version>17</java.version>
<lombok.version>1.18.30</lombok.version>
<mysql.version>8.0.33</mysql.version>
<!-- 统一管理项目版本号 -->
<parentProject.version>1.0-SNAPSHOT</parentProject.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version</version>
</dependency>
</dependencies>
<!-- 子模块版本管理 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>moduleA</artifactId>
<version>${parentProject.version}</version>
</dependency>
</dependencyManagement>
4.2 模块间依赖引用
一个模块可以依赖其他模块,只需在pom.xml中添加对应模块的依赖:
<dependency>
<groupId>com.example</groupId>
<artifactId>moduleA</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
这样,moduleB就可以使用moduleA中定义的类和服务了。
5. 模块配置与自定义属性
5.1 模块特定配置
每个模块可以有自己独立的配置文件(application.yml或application.properties),用于设置模块特定的属性:
# moduleA/src/main/resources/application.yml
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://localhost:3306/moduleA_db
username: root
password: password
custom:
module:
setting: value-specific-to-moduleA
5.2 跨模块配置共享
使用Spring Boot的@ConfigurationProperties
注解,可以创建能够在多个模块间共享的配置类:
// 在common模块中定义
@Component
@ConfigurationProperties(prefix = "sky.aa")
@Data
public class AA {
private String name;
private String age;
}
在其他模块中,只需在配置文件中设置相应属性即可注入使用:
# 在使用模块的application.yml中
sky:
aa:
name: zhan
age: 12
这种机制使得配置能够在模块间共享和重用。
6. 代码实现示例
6.1 创建模块服务类
在每个模块中,可以创建特定的服务类实现业务逻辑:
package com.example.moduleA;
import org.springframework.stereotype.Service;
@Service
public class MyService {
public String getGreeting() {
return "Hello from Module A!";
}
}
6.2 创建REST控制器
package com.example.mymodule.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping
public String sayHello() {
return "Hello from My Module!";
}
}
6.3 主应用类
每个可独立运行的模块需要有自己的主应用类:
package com.example.moduleA;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
7. 构建与测试
7.1 项目构建
使用Maven命令构建整个项目:
# 在父项目目录下执行
mvn clean install
此命令会编译所有模块,运行测试,并安装到本地Maven仓库。
7.2 运行特定模块
要运行特定模块,可以进入模块目录并使用Spring Boot插件:
cd moduleA
mvn spring-boot:run
或者直接在IDE中运行模块的主应用类。
7.3 测试模块间依赖
在依赖其他模块的模块中,可以测试依赖是否正常工作:
import com.example.modulea.ServiceA;
@Service
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void performAction() {
serviceA.action();
}
}
8. 常见问题与解决方案
8.1 模块无法识别问题
如果新模块未被正确识别,检查父pom.xml中的modules配置是否包含了新模块,并确保子模块的parent配置正确指向父项目。
8.2 依赖版本冲突
使用父项目中的dependencyManagement统一管理依赖版本,避免不同模块使用不同版本的依赖库。
8.3 配置不生效
确保模块的配置文件放置在src/main/resources目录下,并且配置属性前缀与@ConfigurationProperties
注解中设置的前缀一致。
8.4 类无法扫描问题
如果模块中的组件未被Spring扫描到,检查主应用类是否在包的根目录下,或者使用@ComponentScan
注解明确指定要扫描的包。