@Autowired
是 Spring 框架中用于依赖注入(Dependency Injection, DI)的核心注解,用于将其他 Bean 注入到当前 Bean 的字段、方法或构造器中。它通过自动装配机制,解耦了对象之间的依赖关系,使代码更简洁、可维护性更高。以下从注解定义、源码解析、核心机制、使用场景及注意事项展开详细说明。
一、@Autowired
注解的定义与源码解析
@Autowired
位于 org.springframework.beans.factory.annotation
包中,其源码定义如下(简化版):
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* 是否必需(默认 true,依赖不存在时抛出异常)
*/
boolean required() default true;
/**
* 限定符(用于解决多个候选 Bean 的歧义,默认空)
*/
String value() default "";
}
关键属性说明:
required
:标记依赖是否必需。若为true
(默认),当容器中无匹配的 Bean 时,抛出NoSuchBeanDefinitionException
;若为false
,依赖不存在时注入null
(仅适用于可选依赖)。value
:可选属性,用于指定 Bean 的名称(当存在多个同类型 Bean 时,通过此属性选择具体 Bean)。
二、核心机制:Spring 如何实现 @Autowired
注入
@Autowired
的注入流程深度依赖 Spring 的 BeanPostProcessor
机制,核心步骤如下:
1. BeanPostProcessor 扫描
Spring 启动时,AutowiredAnnotationBeanPostProcessor
(实现了 BeanPostProcessor
)会被注册到容器中。它负责扫描所有被 @Autowired
标记的字段、方法或构造器。
2. 依赖查找与注入
对于每个被 @Autowired
标记的元素(字段、方法、构造器),AutowiredAnnotationBeanPostProcessor
会:
- 确定依赖类型:根据字段类型、方法参数类型或构造器参数类型,确定需要注入的 Bean 类型。
- 查找候选 Bean:从
BeanFactory
中查找所有匹配类型的 Bean(通过getBeansOfType
方法)。 - 解决歧义:若存在多个候选 Bean,通过以下规则选择:
- 优先选择被
@Primary
标记的 Bean(主候选)。 - 若未标记
@Primary
,但存在@Qualifier
注解(或@Autowired(value = "beanName")
),则按名称匹配。 - 若仍无法确定,抛出
NoUniqueBeanDefinitionException
。
- 优先选择被
- 注入依赖:将找到的 Bean 实例注入到目标位置(字段赋值、方法调用参数、构造器参数)。
3. 循环依赖的处理
若两个 Bean 相互依赖(如 A 依赖 B,B 依赖 A),Spring 会通过早期暴露 Bean 引用解决循环依赖:
- 当 A 被实例化后(尚未完成属性注入),Spring 会将其放入
singletonFactories
缓存中(三级缓存)。 - B 在实例化时需要注入 A,此时从缓存中获取 A 的早期引用(未完成初始化),完成 B 的实例化。
- 最终 A 完成初始化后,B 中的 A 引用会被更新为完整的实例。
三、典型使用场景与示例
1. 字段注入(最常用)
直接在字段上使用 @Autowired
,Spring 会自动将匹配的 Bean 注入到该字段。
示例:
@Service
public class UserService {
// 注入 UserRepository(假设已通过 @Repository 标记)
@Autowired
private UserRepository userRepository;
public User getUser(Long id) {
return userRepository.findById(id).orElseThrow();
}
}
2. 构造器注入(推荐)
通过构造器参数注入依赖,强制依赖在对象创建时完成注入,避免空指针异常,提高代码可测试性。
示例:
@Service
public class OrderService {
private final UserRepository userRepository;
private final PaymentService paymentService;
// 构造器注入(推荐)
@Autowired // 构造器参数顺序与注入顺序一致(Spring 4.3+ 可省略 @Autowired)
public OrderService(UserRepository userRepository, PaymentService paymentService) {
this.userRepository = userRepository;
this.paymentService = paymentService;
}
public void createOrder(Long userId) {
User user = userRepository.findById(userId).orElseThrow();
paymentService.charge(user);
}
}
3. 方法注入
在方法(通常是 setter 方法)上使用 @Autowired
,Spring 会调用该方法并注入参数。
示例:
@Service
public class LogService {
private Logger logger;
// Setter 方法注入
@Autowired
public void setLogger(Logger logger) {
this.logger = logger;
}
public void log(String message) {
logger.info(message);
}
}
4. 注入可选依赖(required = false
)
当依赖可能不存在时,设置 required = false
避免启动失败。
示例:
@Service
public class OptionalService {
private final Optional<CacheService> cacheService;
// required = false,无 CacheService 时注入 null
@Autowired(required = false)
public OptionalService(CacheService cacheService) {
this.cacheService = Optional.ofNullable(cacheService);
}
public void cacheData(String key, Object value) {
cacheService.ifPresent(cs -> cs.put(key, value));
}
}
5. 解决多候选 Bean 歧义(@Qualifier
)
当存在多个同类型 Bean 时,通过 @Qualifier
指定 Bean 名称。
示例:
// 配置类:定义两个 DataSource
@Configuration
public class DataSourceConfig {
@Bean("mysqlDataSource")
public DataSource mysqlDataSource() {
return DataSourceBuilder.create().url("jdbc:mysql://...").build();
}
@Bean("oracleDataSource")
public DataSource oracleDataSource() {
return DataSourceBuilder.create().url("jdbc:oracle:...").build();
}
}
// 服务类:指定注入 mysqlDataSource
@Service
public class DataService {
private final DataSource dataSource;
@Autowired
public DataService(@Qualifier("mysqlDataSource") DataSource dataSource) {
this.dataSource = dataSource;
}
}
四、源码实现细节与关键类
1. AutowiredAnnotationBeanPostProcessor
这是处理 @Autowired
的核心类,继承自 InstantiationAwareBeanPostProcessorAdapter
,主要方法包括:
postProcessProperties
:处理字段、方法参数的注入。postProcessBeforeInstantiation
:处理构造器注入(通过ConstructorResolver
)。
2. ConstructorResolver
负责解析构造器参数并选择匹配的 Bean,处理构造器注入的逻辑。
3. BeanFactory
的 getBean
方法
底层通过 BeanFactory.getBean(Class<T>)
或 getBean(String name, Class<T>)
查找并返回 Bean 实例。
五、注意事项与常见问题
1. 避免字段注入的滥用
字段注入虽然简单,但会导致:
- 类与 Spring 容器紧耦合(无法脱离容器测试)。
- 无法保证依赖的不可变性(字段可被修改)。
推荐:优先使用构造器注入(强制依赖、不可变)。
2. 循环依赖的限制
Spring 仅支持单例 Bean 的循环依赖(通过三级缓存解决),原型(prototype
) Bean 的循环依赖无法解决(每次获取新实例,无法注入未完成的实例)。
3. 类型匹配的规则
- 若注入字段是接口类型,Spring 会查找所有实现该接口的 Bean。
- 若注入字段是具体类类型,Spring 会查找该类的 Bean(或其子类)。
4. 与 @Resource
的区别
特性 | @Autowired | @Resource |
---|---|---|
来源 | Spring 自定义注解 | JSR-250 标准注解(Java EE) |
匹配方式 | 优先按类型,其次按名称(value ) | 优先按名称,其次按类型 |
可选性 | 支持 required 属性 | 不支持(不存在时抛异常) |
适用场景 | Spring 项目 | 跨框架(如与 Java EE 集成) |
5. 性能优化
- 避免在
@Autowired
注入的字段中执行耗时操作(如初始化大对象)。 - 对于无状态的 Bean(如工具类),使用单例作用域(默认),减少实例化开销。
六、总结
@Autowired
是 Spring 依赖注入的核心注解,通过自动装配机制解耦对象依赖。其核心机制依赖 AutowiredAnnotationBeanPostProcessor
和 BeanFactory
的协作,支持字段、构造器、方法等多种注入方式。理解其源码(如循环依赖处理、多候选 Bean 歧义解决)和使用注意事项(如构造器注入的优势、循环依赖限制),有助于开发者编写更健壮、可维护的 Spring 应用。