Spring Boot 多模块自动装配
问题背景
在微服务架构中,通用代码(如全局异常处理、统一响应封装)放在 common 模块,其他服务通过 Maven 依赖引入。
现象:
- ✅ 正常响应:按预期格式返回
- ❌ 异常响应:返回 Spring Boot 默认错误格式,自定义全局异常处理器未生效
// 期望的错误响应
{
"code": 40001,
"message": "用户不存在",
"data": null,
"timestamp": 1764591719827
}
// 实际返回(Spring Boot 默认格式)
{
"timestamp": "2025-12-01T12:19:56.458+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "user not found",
"path": "/user/login"
}
根本原因
Spring Boot 默认组件扫描规则
@SpringBootApplication 默认只扫描 启动类所在包及其子包:
com.canvaschain.user ← 启动类所在包(会扫描)
├── controller/
├── service/
└── UserServiceApplication.java
com.canvaschain.common ← 不在扫描范围内!
├── exception/
│ └── GlobalExceptionHandler.java ← 未被加载
└── config/
结论:GlobalExceptionHandler 没有被 Spring 容器管理,所以不生效。
解决方案
方案一:手动 ComponentScan(不推荐)
@SpringBootApplication
@ComponentScan(basePackages = {"com.canvaschain.user", "com.canvaschain.common"})
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
缺点:
- 每个服务都需要手动添加
- 容易遗漏,维护成本高
方案二:Spring Boot 自动装配(推荐)
1. 创建自动配置类
common 模块中创建:
package com.canvaschain.common.config;
import com.canvaschain.common.exception.GlobalExceptionHandler;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Slf4j
@Configuration
@Import({
GlobalExceptionHandler.class,
// 可以继续添加其他需要自动装配的组件
})
public class CommonAutoConfiguration {
@PostConstruct
public void init() {
log.info("✅ CommonAutoConfiguration 已加载");
}
}
2. 配置自动装配文件
根据 Spring Boot 版本选择:
Spring Boot 2.7 及以下
创建文件:src/main/resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.canvaschain.common.config.CommonAutoConfiguration
Spring Boot 3.x
创建文件:src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.canvaschain.common.config.CommonAutoConfiguration
3. 目录结构
common/
├── pom.xml
└── src/main/
├── java/com/canvaschain/common/
│ ├── config/
│ │ └── CommonAutoConfiguration.java
│ ├── exception/
│ │ ├── BusinessException.java
│ │ ├── GlobalExceptionHandler.java
│ │ └── ThrowUtils.java
│ ├── response/
│ │ ├── BaseResponse.java
│ │ ├── ErrorCode.java
│ │ └── ResultUtils.java
│ └── ...
└── resources/
└── META-INF/
├── spring.factories # Spring Boot 2.x
└── spring/
└── org.springframework.boot.autoconfigure.AutoConfiguration.imports # Spring Boot 3.x
4. 使用方服务(无需任何额外配置)
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
只需在 pom.xml 引入依赖即可自动生效:
<dependency>
<groupId>com.canvaschain</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
自动装配原理
┌─────────────────────────────────────────────────────────────┐
│ Spring Boot 启动流程 │
├─────────────────────────────────────────────────────────────┤
│ 1. @SpringBootApplication 触发自动配置 │
│ ↓ │
│ 2. 扫描所有 jar 包中的 META-INF/spring.factories │
│ 或 META-INF/spring/...AutoConfiguration.imports │
│ ↓ │
│ 3. 加载配置的 AutoConfiguration 类 │
│ ↓ │
│ 4. @Import 导入的组件被注册到 Spring 容器 │
│ ↓ │
│ 5. GlobalExceptionHandler 生效 │
└─────────────────────────────────────────────────────────────┘
验证方法
1. 查看启动日志
✅ CommonAutoConfiguration 已加载
2. 检查 Bean 是否注册
@SpringBootTest
class AutoConfigTest {
@Autowired
private ApplicationContext context;
@Test
void testGlobalExceptionHandlerLoaded() {
boolean exists = context.containsBean("globalExceptionHandler");
assertTrue(exists, "GlobalExceptionHandler 应该被自动装配");
}
}
3. 测试异常响应
curl -X POST http://localhost:8080/user/login \
-H "Content-Type: application/json" \
-d '{"username":"notexist","password":"123456"}'
期望返回:
{
"code": 40004,
"message": "用户不存在",
"data": null,
"timestamp": 1764591719827
}
方案对比
| 特性 | 手动 ComponentScan | 自动装配(spring.factories) |
|---|---|---|
| 配置方式 | 每个服务手动配置 | 一次配置,自动生效 |
| 维护成本 | 高,容易遗漏 | 低,对使用方透明 |
| 扩展性 | 差 | 好,类似 Spring Boot Starter |
| 推荐度 | ❌ | ✅ |
常见问题
Q1: 两个配置文件都需要吗?
不需要,根据 Spring Boot 版本选择一个:
- Spring Boot 2.7 及以下:
spring.factories - Spring Boot 3.x:
AutoConfiguration.imports - 兼容两个版本:两个文件都配置
Q2: 自动装配不生效怎么排查?
- 检查配置文件路径是否正确
- 检查类的全限定名是否正确
- 检查 common 模块是否被正确打包(
mvn clean install) - 启动时添加
--debug查看自动配置报告
java -jar app.jar --debug
Q3: 如何有条件地启用自动配置?
@Configuration
@ConditionalOnProperty(name = "common.exception.enabled", havingValue = "true", matchIfMissing = true)
@Import(GlobalExceptionHandler.class)
public class CommonAutoConfiguration {
}
参考资料
- Spring Boot 官方文档 - Creating Your Own Auto-configuration
- Spring Boot 2.7 Release Notes - Auto-configuration Changes
项目分区导航:⬅️ 02-异常处理最佳实践代码 | 03-Spring Boot 多模块自动装配 | ➡️ 00-接口文档
💬 评论