Spring依赖注入原理及使用
Spring依赖注入原理及使用
一、四种注入方式详解
1. @Autowired 注入
实现原理
- 基于类型(Type)的依赖注入
- 通过
AutowiredAnnotationBeanPostProcessor实现 - 利用Java反射获取注解信息,在Bean实例化后、初始化前完成注入
- 默认按类型匹配,如果存在多个同类型Bean,会结合
@Primary或@Qualifier进一步筛选
@Service
public class UserService {
@Autowired
private UserDao userDao; // 字段注入
@Autowired
public UserService(OrderService orderService) { // 构造器注入(推荐)
this.orderService = orderService;
}
}
优缺点
| 优点 | 缺点 |
|---|---|
| 简洁,代码量少 | 字段注入:无法使用final,不利于单元测试 |
| Spring原生支持,功能丰富 | 依赖对使用者不透明(隐藏依赖) |
| 支持required=false灵活控制 | 循环依赖时可能产生问题 |
2. @Resource 注入
实现原理
- JSR-250标准注解,JDK原生支持
- 通过
CommonAnnotationBeanPostProcessor实现 - 先按名称(Name)匹配,找不到再按类型匹配
- 属于Java EE规范,降低与Spring的耦合
@Service
public class UserService {
@Resource(name = "userDaoImpl") // 指定名称
private UserDao userDao;
@Resource // 默认按字段名查找
private OrderService orderService;
}
优缺点
| 优点 | 缺点 |
|---|---|
| 标准规范,可移植性强 | 功能不如@Autowired丰富(无required属性) |
| 默认按名称匹配,意图明确 | Spring特有高级功能支持有限 |
| 降低框架耦合 | 只能用于字段和setter,不支持构造器 |
3. 构造器注入(Constructor Injection)
实现原理
- Spring 4.3+ 推荐方式,Spring Boot 2.0+ 默认行为
- 通过
ConstructorResolver解析构造器参数 - 利用参数类型自动匹配依赖Bean
- 无需@Autowired,单个构造器自动识别
@Service
public class UserService {
private final UserDao userDao;
private final OrderService orderService;
// Spring 4.3+ 单个构造器无需@Autowired
public UserService(UserDao userDao, OrderService orderService) {
this.userDao = userDao;
this.orderService = orderService;
}
}
优缺点
| 优点 | 缺点 |
|---|---|
| ✅ 依赖不可变(可用final) | 参数过多时构造器臃肿 |
| ✅ 保证依赖不为null | 循环依赖时启动报错(严格但安全) |
| ✅ 代码更清晰,依赖一目了然 | 需要为测试提供所有依赖 |
| ✅ 避免NPE,对象完全构造后可用 | |
| ✅ 无需@Autowired,更简洁 |
4. Setter 注入(Setter Injection)
实现原理
- 通过
AutowiredAnnotationBeanPostProcessor处理setter方法上的@Autowired - 在Bean实例化后调用setter方法注入依赖
- 支持可选依赖(非强制)
@Service
public class UserService {
private UserDao userDao;
private Optional<CacheService> cacheService;
@Autowired(required = true) // 必需依赖
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Autowired(required = false) // 可选依赖
public void setCacheService(CacheService cacheService) {
this.cacheService = Optional.ofNullable(cacheService);
}
}
优缺点
| 优点 | 缺点 |
|---|---|
| 可选依赖灵活控制 | 对象可能处于不完全状态 |
| 可在运行时重新注入 | 无法使用final,依赖可变 |
| 解决部分循环依赖场景 | 需要额外编写setter代码 |
| 单元测试需要模拟setter调用 |
二、Spring Boot 3 中的使用情况
🔥 Spring Boot 3 官方推荐(重大变化)
Spring Boot 3(基于Spring Framework 6)强烈推荐构造器注入,并有一些重要变化:
| 特性 | Spring Boot 2.x | Spring Boot 3.x |
|---|---|---|
| 推荐方式 | 构造器注入(推荐) | 构造器注入(强制推荐) |
| 字段注入 | 可用但不推荐 | 强烈不建议 |
| @Autowired | 常用于字段 | 主要用于配置类或可选依赖 |
| Lombok配合 | @RequiredArgsConstructor | @RequiredArgsConstructor(标准做法) |
| AOP代理 | 构造器注入需注意 | CGLIB代理优化,构造器注入更稳定 |
Spring Boot 3 最佳实践代码
@Service
@RequiredArgsConstructor // Lombok生成构造器,现代Spring Boot标准写法
public class UserService {
private final UserDao userDao; // 必需依赖
private final OrderService orderService; // 必需依赖
// 可选依赖使用setter或ObjectProvider
private final ObjectProvider<CacheService> cacheServiceProvider;
public void process() {
// 延迟获取可选依赖
cacheServiceProvider.ifAvailable(CacheService::clear);
}
}
// 配置类示例
@Configuration
public class AppConfig {
private final DataSource dataSource;
// 配置类也推荐构造器注入
public AppConfig(DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource);
}
}
三、实际项目使用建议
决策流程图
开始选择注入方式
│
├─ 是否必需依赖且不可变? ──→ 构造器注入(首选)
│ │
│ 参数过多? → 考虑拆分或Facade模式
│
├─ 是否可选依赖? ────────→ Setter注入 或 ObjectProvider
│
├─ 是否需要降低框架耦合? ──→ @Resource(如跨框架复用)
│
└─ 快速原型/遗留系统维护 ──→ @Autowired字段注入(临时)
各场景推荐方案
| 场景 | 推荐方式 | 代码示例 |
|---|---|---|
| 标准业务Service | 构造器 + Lombok | @RequiredArgsConstructor |
| 配置属性类 | 构造器注入 | @ConfigurationProperties + 构造器绑定 |
| 可选功能组件 | Setter或ObjectProvider | ObjectProvider<MetricsService> |
| 多实现策略模式 | 构造器 + Map/List | Map<String, Strategy> 注入所有实现 |
| 循环依赖 | Setter注入(重构优先) | @Autowired on setter |
| 单元测试 | 构造器最友好 | 直接new,无需反射 |
现代Spring Boot 3项目标准模板
// Controller层
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService; // 构造器注入
private final UserMapper userMapper;
}
// Service层
@Service
@RequiredArgsConstructor
@Slf4j
public class UserService {
private final UserRepository userRepository;
private final EventPublisher eventPublisher;
private final ObjectProvider<AuditService> auditService; // 可选
@Transactional
public User createUser(UserDTO dto) {
// 业务逻辑
auditService.ifAvailable(service -> service.audit("CREATE"));
}
}
// 基础设施层
@Component
public class EventPublisher {
private final ApplicationEventPublisher publisher;
private final ObjectProvider<TransactionTemplate> txTemplate; // 可选事务
public EventPublisher(ApplicationEventPublisher publisher,
ObjectProvider<TransactionTemplate> txTemplate) {
this.publisher = publisher;
this.txTemplate = txTemplate;
}
}
四、关键对比总结
| 维度 | @Autowired字段 | @Autowired构造器 | @Resource | Setter注入 |
|---|---|---|---|---|
| Spring Boot 3推荐度 | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 依赖可见性 | 差 | 极好 | 差 | 一般 |
| 不可变性(final) | ❌ | ✅ | ❌ | ❌ |
| 空安全 | 运行时风险 | 编译期保证 | 运行时风险 | 运行时风险 |
| 测试友好度 | 差(需反射/容器) | 极好(直接new) | 差 | 一般 |
| 循环依赖检测 | 弱(可能隐藏) | 强(启动报错) | 弱 | 中等 |
| 启动速度 | 慢(反射多) | 快 | 慢 | 慢 |
Spring Boot 3 黄金法则:
能用构造器注入就用构造器注入,配合Lombok的
@RequiredArgsConstructor实现最简洁、最安全的依赖管理。

浙公网安备 33010602011771号