当@Autowired谈恋爱时,Spring在后台偷偷做了什么?

64 阅读3分钟

当@Autowired谈恋爱时,Spring在后台偷偷做了什么?

老张走进咖啡馆,对服务员说:"给我一杯拿铁,加糖加奶,温度70度,奶泡厚度1厘米..."。服务员微微一笑:"好的先生,您需要的所有材料已经在后厨准备好了,马上为您调配。"

这个场景像极了Spring容器中@Autowired的工作方式——你只需说出需求(声明依赖),Spring这个"咖啡师"就会在幕后自动调配所有原料(依赖注入)。今天我们就来扒一扒这个魔法背后的秘密。

一、@Autowired的"月老"之路

1.1 BeanPostProcessor:Spring的婚介所

每个被@Autowired标记的字段/方法,都会进入Spring的"相亲名单"。这个红娘角色由AutowiredAnnotationBeanPostProcessor扮演(名字长到需要换气的Bean后处理器)。

它会在Bean初始化阶段做两件大事:

  1. 扫描所有待嫁Bean的"征婚启事"(解析@Autowired注解)
  2. 拿着生辰八字(类型/名称)去婚介所(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会开启"牵红线"流程:

  1. 按图索骥:遍历所有需要注入的字段/方法
  2. 大海捞针:根据类型在容器中匹配候选Bean
  3. 优中选优:当有多个候选时,用@Qualifier指定意中人
  4. 终成眷属:通过反射将匹配的Bean注入目标位置

二、三级缓存:Spring的恋爱兵法

2.1 循环依赖:先结婚后恋爱的骚操作

当A依赖B,B又依赖A时,Spring祭出三级缓存大法:

缓存级别存储内容作用
singletonObjects完全体Bean直接拿来用
earlySingletonObjects半成品Bean(刚实例化未初始化)解决循环依赖
singletonFactoriesObjectFactory工厂生成代理对象的回调接口

处理流程就像相亲时的"先见家长后培养感情":

  1. 把刚new出来的A(半成品)放进三级缓存
  2. 给A注入属性时发现需要B
  3. 开始创建B,B又需要A
  4. 从三级缓存拿到A的引用(虽然是半成品)
  5. 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 防坑指南

  1. 推荐使用构造器注入(Spring4.3+可以省略@Autowired)
  2. 对可选依赖使用@Autowired(required=false)
  3. 用@Qualifier给Bean起小名
  4. 在配置类用@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(包)...