当@Autowired谈恋爱时,Spring在后台偷偷做了什么?
老张走进咖啡馆,对服务员说:"给我一杯拿铁,加糖加奶,温度70度,奶泡厚度1厘米..."。服务员微微一笑:"好的先生,您需要的所有材料已经在后厨准备好了,马上为您调配。"
这个场景像极了Spring容器中@Autowired的工作方式——你只需说出需求(声明依赖),Spring这个"咖啡师"就会在幕后自动调配所有原料(依赖注入)。今天我们就来扒一扒这个魔法背后的秘密。
一、@Autowired的"月老"之路
1.1 BeanPostProcessor:Spring的婚介所
每个被@Autowired标记的字段/方法,都会进入Spring的"相亲名单"。这个红娘角色由AutowiredAnnotationBeanPostProcessor扮演(名字长到需要换气的Bean后处理器)。
它会在Bean初始化阶段做两件大事:
- 扫描所有待嫁Bean的"征婚启事"(解析@Autowired注解)
- 拿着生辰八字(类型/名称)去婚介所(BeanFactory)匹配对象
// 伪代码揭秘红娘工作流程
public class AutowiredAnnotationBeanPostProcessor {
public void postProcessMergedBeanDefinition(BeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 拿着放大镜找所有标注@Autowired的部位
InjectionMetadata metadata = findAutowiredMetadata(beanName, beanType);
// 记录这个Bean的脱单需求
metadata.checkConfigMembers(beanDefinition);
}
}
1.2 依赖注入四部曲
当Bean实例化后,Spring会开启"牵红线"流程:
- 按图索骥:遍历所有需要注入的字段/方法
- 大海捞针:根据类型在容器中匹配候选Bean
- 优中选优:当有多个候选时,用@Qualifier指定意中人
- 终成眷属:通过反射将匹配的Bean注入目标位置
二、三级缓存:Spring的恋爱兵法
2.1 循环依赖:先结婚后恋爱的骚操作
当A依赖B,B又依赖A时,Spring祭出三级缓存大法:
| 缓存级别 | 存储内容 | 作用 |
|---|---|---|
| singletonObjects | 完全体Bean | 直接拿来用 |
| earlySingletonObjects | 半成品Bean(刚实例化未初始化) | 解决循环依赖 |
| singletonFactories | ObjectFactory工厂 | 生成代理对象的回调接口 |
处理流程就像相亲时的"先见家长后培养感情":
- 把刚new出来的A(半成品)放进三级缓存
- 给A注入属性时发现需要B
- 开始创建B,B又需要A
- 从三级缓存拿到A的引用(虽然是半成品)
- B创建完成后,A继续完成属性注入
2.2 源码中的爱情三十六计
在DefaultSingletonBeanRegistry中,我们可以看到这样的代码:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
三、坑爹名场面:@Autowired的翻车现场
3.1 经典翻车案例
- NPE惊魂:在构造函数中使用@Autowired字段
- 花心大萝卜:同类型多个Bean不指定@Qualifier
- 单相思悲剧:要注入的Bean根本没在容器注册
- 代理对象之谜:AOP生成的代理对象导致instanceof判断失效
3.2 防坑指南
- 推荐使用构造器注入(Spring4.3+可以省略@Autowired)
- 对可选依赖使用@Autowired(required=false)
- 用@Qualifier给Bean起小名
- 在配置类用@Bean明确生产方式
// 正确姿势示例
@Service
public class OrderService {
private final UserService userService;
public OrderService(@Qualifier("vipUserService") UserService userService) {
this.userService = userService; // 构造器注入更安全
}
}
四、写给程序员的爱情哲学
当我们深入@Autowired的实现,会发现处处体现着设计模式的智慧:
- 中介者模式:BeanFactory协调各方关系
- 策略模式:不同的依赖解析策略
- 模板方法:定义Bean创建的生命周期
Spring就像个经验丰富的红娘,在保持灵活性的同时严守底线(比如默认的单例模式防止渣男遍地)。下次当你的Bean成功注入时,不妨对Spring说声:谢谢啊,老铁!
最后送大家一个冷笑话:为什么@Autowired和@Resource不能在一起?因为它们是两个不同的package(包)...