Spring Boot 多模块开发完整指南
Spring Boot 多模块开发完整指南
Spring Boot 多模块开发是将一个大型项目拆分成多个相互关联的模块,每个模块有特定的职责。这种架构提高了代码的可维护性、可复用性和团队协作效率。
1. 多模块项目结构
1.1 典型的项目结构
my-project/
├── pom.xml (父POM)
├── common/ (通用模块)
│ ├── src/
│ └── pom.xml
├── domain/ (领域模型模块)
│ ├── src/
│ └── pom.xml
├── service/ (业务逻辑模块)
│ ├── src/
│ └── pom.xml
├── web/ (Web接口模块)
│ ├── src/
│ └── pom.xml
└── application/ (主应用模块)
├── src/
└── pom.xml
2. 创建多模块项目
2.1 创建父项目
父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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-multi-module-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging> <!-- 关键:父模块打包方式为pom -->
<name>My Multi Module Project</name>
<description>Spring Boot多模块项目示例</description>
<!-- 模块声明 -->
<modules>
<module>common</module>
<module>domain</module>
<module>service</module>
<module>web</module>
<module>application</module>
</modules>
<!-- 父POM使用Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/>
</parent>
<properties>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 依赖管理 -->
<dependencyManagement>
<dependencies>
<!-- 内部模块版本管理 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>domain</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>service</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>web</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 公共依赖 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2.2 创建common模块
common/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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>my-multi-module-project</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>common</artifactId>
<packaging>jar</packaging>
<dependencies>
<!-- 通用工具类依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
</project>
common模块代码示例:
// common/src/main/java/com/example/common/Result.java
package com.example.common;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Result<T> {
private Integer code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("success");
result.setData(data);
return result;
}
public static <T> Result<T> error(String message) {
Result<T> result = new Result<>();
result.setCode(500);
result.setMessage(message);
return result;
}
}
// common/src/main/java/com/example/common/constants/ErrorCode.java
package com.example.common.constants;
public class ErrorCode {
public static final int SUCCESS = 200;
public static final int BAD_REQUEST = 400;
public static final int UNAUTHORIZED = 401;
public static final int NOT_FOUND = 404;
public static final int INTERNAL_ERROR = 500;
}
2.3 创建domain模块
domain/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://aven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>my-multi-module-project</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>domain</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
</project>
domain模块代码示例:
// domain/src/main/java/com/example/domain/user/entity/User.java
package com.example.domain.user.entity;
import lombok.Data;
import javax.persistence.*;
@Data
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String password;
private String email;
private String phone;
}
// domain/src/main/java/com/example/domain/user/repository/UserRepository.java
package com.example.domain.user.repository;
import com.example.domain.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
boolean existsByUsername(String username);
}
2.4 创建service模块
service/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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>my-multi-module-project</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>service</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>domain</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
service模块代码示例:
// service/src/main/java/com/example/service/user/UserService.java
package com.example.service.user;
import com.example.domain.user.entity.User;
import com.example.domain.user.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User createUser(String username, String password, String email) {
if (userRepository.existsByUsername(username)) {
throw new RuntimeException("用户名已存在");
}
User user = new User();
user.setUsername(username);
user.setPassword(password); // 实际应用中需要加密
user.setEmail(email);
return userRepository.save(user);
}
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("用户不存在"));
}
public User getUserByUsername(String username) {
return userRepository.findByUsername(username);
}
}
2.5 创建web模块
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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>my-multi-module-project</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>web</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>service</artifactId>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
web模块代码示例:
// web/src/main/java/com/example/web/controller/UserController.java
package com.example.web.controller;
import com.example.common.Result;
import com.example.domain.user.entity.User;
import com.example.service.user.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public Result<User> createUser(@RequestBody User user) {
try {
User createdUser = userService.createUser(
user.getUsername(),
user.getPassword(),
user.getEmail()
);
return Result.success(createdUser);
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@GetMapping("/{id}")
public Result<User> getUser(@PathVariable Long id) {
try {
User user = userService.getUserById(id);
return Result.success(user);
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
}
// web/src/main/java/com/example/web/config/WebConfig.java
package com.example.web.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE");
}
}
2.6 创建application模块(主启动模块)
application/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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>my-multi-module-project</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>application</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application模块代码示例:
// application/src/main/java/com/example/Application.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication(scanBasePackages = "com.example")
@EntityScan("com.example.domain")
@EnableJpaRepositories("com.example.domain")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// application/src/main/resources/application.yml
server:
port: 8080
servlet:
context-path: /api
spring:
datasource:
url: jdbc:mysql://localhost:3306/myapp?useSSL=false&serverTimezone=UTC
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
logging:
level:
com.example: DEBUG
3. 构建和运行
3.1 构建整个项目
在项目根目录执行:
mvn clean install
3.2 运行应用
cd application
mvn spring-boot:run
3.3 打包部署
# 打包整个项目
mvn clean package
# 只运行application模块的测试
cd application
mvn test
# 跳过测试打包
mvn clean package -DskipTests
4. 高级配置和最佳实践
4.1 配置文件分离
# application-dev.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/myapp_dev
# application-prod.yml
spring:
datasource:
url: jdbc:mysql://prod-db:3306/myapp_prod
4.2 自定义Starter模块
可以创建自定义starter模块供其他项目使用:
custom-starter/pom.xml:
<project>
<!-- ... -->
<artifactId>custom-spring-boot-starter</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
4.3 模块间测试
// 在service模块中测试
@SpringBootTest(classes = TestConfig.class)
class UserServiceTest {
@Autowired
private UserService userService;
@Test
void testCreateUser() {
// 测试逻辑
}
@Configuration
@Import(UserService.class)
static class TestConfig {
@Bean
public UserRepository userRepository() {
return mock(UserRepository.class);
}
}
}
5. 常见问题解决
5.1 模块依赖循环
- 使用接口分离依赖
- 重构模块职责
5.2 组件扫描问题
- 确保主类在根包下
- 使用
@ComponentScan指定扫描路径
5.3 配置文件优先级
1. 命令行参数
2. application-{profile}.yml
3. application.yml
4. 模块内的配置文件

浙公网安备 33010602011771号