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实现最简洁、最安全的依赖管理。

posted @ 2026-03-25 10:10  itteer  阅读(22)  评论(0)    收藏  举报