Spring中@Autowired注解的实现原理
@Autowired是Spring依赖注入的核心注解,其实现依赖于Spring的Bean生命周期 和后处理器机制。以下是详细的实现流程:
一、核心组件:AutowiredAnnotationBeanPostProcessor
@Autowired的处理由org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor类完成,这是一个BeanPostProcessor (Bean后处理器),用于在Bean初始化前后拦截并处理注解。
1. BeanPostProcessor的作用
- 用于扩展Spring的Bean创建过程
- 提供两个核心方法:
postProcessBeforeInitialization:Bean初始化前调用postProcessAfterInitialization:Bean初始化后调用
AutowiredAnnotationBeanPostProcessor主要在Bean实例化后、初始化前 处理@Autowired注解
二、@Autowired的处理流程
1. 初始化:注册AutowiredAnnotationBeanPostProcessor
Spring容器启动时,会自动注册AutowiredAnnotationBeanPostProcessor(通过@EnableAnnotationConfig或@SpringBootApplication间接启用)。
2. 扫描:识别@Autowired注解
在Bean实例化后,AutowiredAnnotationBeanPostProcessor会:
- 遍历Bean的所有字段 、构造方法 、setter方法
- 检查是否带有
@Autowired、@Value、@Inject(JSR-330)注解 - 将识别到的注入点缓存起来,后续统一处理
3. 注入:依赖查找与注入
对于每个注入点,执行以下流程:
步骤1:解析注入点元信息
java
// 简化的注入点解析逻辑
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
// 遍历类的所有字段
for (Field field : clazz.getDeclaredFields()) {
// 检查是否带有@Autowired注解
if (field.isAnnotationPresent(Autowired.class)) {
// 创建注入点元信息
elements.add(new AutowiredFieldElement(field));
}
}
// 遍历构造方法和setter方法(类似逻辑)
return new InjectionMetadata(clazz, elements);
}
步骤2:依赖查找(核心逻辑)
对于每个注入点,AutowiredAnnotationBeanPostProcessor会通过BeanFactory查找匹配的Bean:
- 按类型查找 (byType):优先根据注入点的类型查找所有匹配的Bean
- 按名称查找 (byName):如果指定了
@Qualifier,则结合名称过滤 - 处理歧义 :
- 若找到唯一Bean:直接注入
- 若找到多个Bean :
- 检查是否有
@Primary注解的Bean(优先注入) - 检查是否有
@Qualifier指定名称的Bean - 否则抛出
NoUniqueBeanDefinitionException
- 检查是否有
- 若未找到Bean :
- 检查
@Autowired的required属性(默认为true) - 若
required=true:抛出NoSuchBeanDefinitionException - 若
required=false:跳过注入,注入点设为null
- 检查
步骤3:反射注入
找到匹配的Bean后,通过反射将Bean注入到目标对象:
- 字段注入 :直接设置字段值(需调用
field.setAccessible(true)突破封装) - 构造方法注入:调用构造方法创建Bean实例(Spring 4.3+推荐,支持循环依赖处理)
- setter方法注入:调用setter方法设置值
4. 循环依赖处理
Spring通过三级缓存 解决@Autowired的循环依赖问题:
- 一级缓存(singletonObjects):存储完全初始化的Bean
- 二级缓存(earlySingletonObjects):存储提前暴露的Bean(未完全初始化)
- 三级缓存(singletonFactories):存储Bean的工厂对象,用于生成提前暴露的Bean
处理流程:
- Bean A实例化后,将自己的工厂对象放入三级缓存
- Bean A处理
@Autowired时,依赖Bean B,开始创建Bean B - Bean B实例化后,将自己的工厂对象放入三级缓存
- Bean B处理
@Autowired时,依赖Bean A,从三级缓存获取Bean A的工厂对象,生成提前暴露的Bean A,放入二级缓存 - Bean B注入Bean A后,完成初始化,放入一级缓存
- Bean A注入Bean B后,完成初始化,放入一级缓存
三、核心源码解析
1. AutowiredAnnotationBeanPostProcessor的核心方法
java
// BeanPostProcessor的核心方法:Bean初始化前处理
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 1. 解析当前Bean的所有@Autowired注入点
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 2. 执行依赖注入
metadata.inject(bean, beanName, pvs);
} catch (Exception ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
2. 注入点的注入逻辑
java
// InjectionMetadata.InjectedElement的inject方法(字段注入示例)
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
// 从缓存获取依赖(避免重复查找)
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
} else {
// 构造依赖描述符
DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
descriptor.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
// 3. 核心:通过BeanFactory查找依赖Bean
TypeConverter typeConverter = beanFactory.getTypeConverter();
value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
// 缓存依赖(优化性能)
cacheFieldValue(beanName, value);
}
if (value != null) {
// 4. 反射注入:突破封装,设置字段值
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
四、@Autowired与其他注入注解的区别
| 特性 | @Autowired | @Resource | @Inject |
|---|---|---|---|
| 来源 | Spring原生注解 | JDK原生注解(javax.annotation) | JSR-330标准注解 |
| 注入方式 | byType优先,配合@Qualifier byName | byName优先,fallback to byType | byType优先,配合@Named byName |
| 支持的注入点 | 字段、构造方法、setter方法 | 字段、setter方法 | 字段、构造方法、setter方法 |
| required属性 | 支持(默认为true) | 不支持(找不到Bean抛异常) | 不支持(找不到Bean抛异常) |
| 与Spring集成度 | 高(支持@Primary、@Qualifier) | 低(不支持Spring特定注解) | 中(支持JSR-330标准) |
五、最佳实践与注意事项
1. 优先使用构造方法注入
Spring 4.3+推荐构造方法注入,原因:
- 强制依赖显式声明(避免NullPointerException)
- 支持final字段注入(不可变对象,更安全)
- 有利于单元测试(可直接通过构造方法传入依赖)
2. 避免字段注入的滥用
字段注入虽然简洁,但存在以下问题:
- 依赖关系不明显(需要查看源码才能知道依赖了哪些Bean)
- 不利于单元测试(无法通过构造方法或setter方法注入mock对象)
- 破坏封装性(需要反射突破private修饰符)
3. 合理使用@Qualifier和@Primary
@Qualifier:按名称注入,解决同类型多个Bean的冲突@Primary:标记首选Bean,当有多个同类型Bean时优先注入
六、总结
@Autowired的实现是Spring依赖注入机制的核心体现,其设计思想包括:
- 解耦:通过注解替代硬编码依赖,提高代码的灵活性和可维护性
- 扩展:基于后处理器机制,便于扩展和定制
- 智能:支持多种注入方式和歧义处理,提供良好的开发体验
- 安全:通过三级缓存解决循环依赖,保证Bean的正确初始化
理解@Autowired的实现原理,有助于深入掌握Spring的依赖注入机制,为设计和开发复杂的Spring应用打下基础。
面试延伸点:
- Spring 4.3+为什么推荐构造方法注入?
@Autowired如何解决循环依赖?@Autowired与@Resource的核心区别是什么?AutowiredAnnotationBeanPostProcessor的工作原理?