目录
1、整体流程
2、查找 Bean 规则(@Autowired)
① 优先按类型查找 byType
情况 1:容器中该类型只有 1 个 Bean → 直接注入。
情况 2:同类型多个 Bean(多个实现类)
required 属性
3、三种注入位置区别
1)字段注入(不推荐)
2)setter 方法注入
3)构造器注入(Spring 官方推荐)
4、@Resource 和 @Autowired 对比(高频面试)
5、核心源码链路(精简)
6、循环依赖与自动装配
7、常见坑
面试简答版(背)
自动装配:Spring 根据类型,自动在容器中查找 Bean,完成依赖注入,对应
@Autowired。 核心类:AutowiredAnnotationBeanPostProcessor,它是 Bean 后置处理器,在 Bean 实例化完成之后、初始化之前执行依赖注入。
1、整体流程
- Spring 启动,扫描所有
@Autowired/@Value注解,由AutowiredAnnotationBeanPostProcessor解析。 - Bean 实例化(构造器执行完成,对象已经 new 出来)。
- 执行后置处理器
postProcessProperties,解析当前类的字段、set 方法上的 @Autowired。 - 根据依赖的类型去
BeanFactory查找匹配 Bean。 - 找到之后通过反射给字段 / 方法赋值,完成注入。
- 之后才执行
@PostConstruct、InitializingBean 初始化逻辑。
⚠️ 关键点:实例化 ≠ 初始化
- 实例化:new 对象
- 自动装配(依赖注入)发生在实例化之后,初始化之前。
2、查找 Bean 规则(@Autowired)
① 优先按类型查找byType
java
@Autowired private UserService userService;去容器找UserService类型的 Bean。
情况 1:容器中该类型只有 1 个 Bean → 直接注入。
情况 2:同类型多个 Bean(多个实现类)
- 按类型查到多个,再用变量名(字段名)作为 beanName二次匹配。
- 仍然匹配失败,抛出
NoUniqueBeanDefinitionException。 - 此时可以搭配
@Qualifier("beanName")指定 bean 名称,限定查找。
java
@Autowired @Qualifier("userServiceImpl2") private UserService userService;required 属性
@Autowired(required = false)
required=true(默认):找不到 Bean 直接抛异常。required=false:找不到就置为 null,不报错。
3、三种注入位置区别
1)字段注入(不推荐)
java
@Autowired private UserService userService;- 通过反射直接给 private 字段赋值。
- 缺点:循环依赖不易察觉、不利于单元测试、容易产生 NPE。
2)setter 方法注入
java
@Autowired public void setUserService(UserService userService){ this.userService = userService; }解析 setXxx 方法参数类型,查找 Bean 调用方法赋值。
3)构造器注入(Spring 官方推荐)
Spring4.3 优化:类只有一个构造函数时,@Autowired 可以省略,自动构造器注入。
java
@Autowired public UserController(UserService userService){ this.userService = userService; }注意:构造器注入发生在实例化阶段,对象还没 new 完成,和字段 /set 注入时机不一样。
4、@Resource 和 @Autowired 对比(高频面试)
| 特性 | @Autowired(Spring) | @Resource (JSR‑250 Java 标准) |
|---|---|---|
| 来源 | Spring 注解 | Java 官方 |
| 默认规则 | byType,类型优先,再匹配 name | byName名字优先,名字找不到退化成 byType |
| required | 支持required=false | 不支持 |
| @Qualifier | 配合使用 | 使用name="beanName" |
java
@Resource(name="userServiceImpl1") private UserService userService;5、核心源码链路(精简)
AutowiredAnnotationBeanPostProcessor
postProcessProperties()→ 入口findAutowiringMetadata():收集类上所有 @Autowired 标记的字段、方法元数据InjectionMetadatainject():执行注入- 字段:
Field反射 set - 方法:反射调用方法
- 字段:
beanFactory.resolveDependency():核心方法,解析依赖,去容器查找 BeandoResolveDependency()findAutowireCandidates():根据 type 找到所有候选 Bean- 判断数量:单个直接返回;多个按字段名匹配 beanName;冲突抛异常。
6、循环依赖与自动装配
- 构造器注入会直接循环依赖报错:实例化阶段互相需要对方,对象创建不出来。
- 字段 /setter @Autowired 可以解决循环依赖:依靠 Spring 三级缓存。
- A 先实例化,放入三级缓存;A 需要 B,开始创建 B;B 又需要 A,从缓存拿到半成品 A;B 完成;再注入 A,完成装配。
三级缓存只能解决:singleton 单例、setter / 字段注入,原型 prototype 不支持循环依赖。
7、常见坑
@Autowired接口,多个实现类忘记@Qualifier→NoUniqueBeanDefinitionException。@Autowired(required=false)没判断 null,运行 NPE。- 构造器多个构造函数,不写
@Autowired,Spring 不知道选哪个构造器,启动失败。 this.xxx获取自动装配对象为 null:this 是 new 出来的普通对象,不是 Spring 容器 Bean,不会走后置处理器注入。
面试简答版(背)
@Autowired自动装配由AutowiredAnnotationBeanPostProcessor后置处理器实现。在 Bean 实例化完成之后,解析字段、set 方法注解,优先按类型 byType从容器查找 Bean;如果找到多个同类型 Bean,再使用字段名作为 beanName 匹配;配合@Qualifier可以显式指定 Bean 名称。required控制找不到是否抛异常。
@Resource是 Java 标准注解,默认按名称 byName 查找,找不到才降级按类型。 构造器注入如果只有一个构造器,注解可以省略;构造器注入无法解决循环依赖,字段 setter 注入依靠三级缓存可以处理单例循环依赖。