主题
概念卡片:Spring 依赖注入与 IoC
一句话机制
IoC(控制反转)是「把创建对象、管理依赖的控制权从程序反转到容器」的思想,DI(依赖注入)是它的具体实现——容器创建 Bean 后,自动把被依赖对象注入调用者,调用者无需 new、无需主动获取。 这是 Spring 松耦合的根基。
IoC vs DI
- IoC:控制反转,思想/原则(谁控制依赖的创建?由容器)
- DI:依赖注入,实现手段(容器怎么把依赖给调用者)
类比:IoC 是「不要自己做饭,去食堂吃」的原则,DI 是「食堂把菜端到你桌上」的具体动作。
三种注入方式
| 方式 | 机制 | 特点 |
|---|---|---|
| setter 注入 | 无参构造创建后,调 setter 注入 | 先创建再注入,可选依赖灵活 |
| 构造器注入 | 调带参构造器直接注入 | 创建即完成注入,依赖强制必需 |
| 字段注入 | 反射直接赋值字段(@Autowired 字段) | 最简洁,但难测试、掩盖依赖 |
官方推荐:构造器注入为主(依赖必需、不可变、易测试),setter 注入用于可选依赖,避免字段注入(隐式依赖、难做单元测试)。
java
// 推荐:构造器注入
public class Chinese {
private final Axe axe; // final,不可变
public Chinese(Axe axe) { this.axe = axe; }
}
// 不推荐:字段注入
public class Chinese {
@Autowired
private Axe axe; // 隐式依赖,测试难注入
}@Autowired vs @Resource(面试高频)
| 维度 | @Autowired(Spring) | @Resource(JSR-250) |
|---|---|---|
| 提供方 | Spring | JDK 标准(javax.annotation) |
| 匹配顺序 | byType 优先,多个同类型再 byName(配 @Qualifier) | byName 优先,找不到再 byType |
| 是否必须 | 默认必须(required=true),可 @Autowired(required=false) | 默认必须 |
关键区别一句话:@Autowired 按类型(byType)注入,@Resource 按名称(byName)注入。当接口有多个实现时,@Autowired 需配 @Qualifier 指定,@Resource 用 name 指定。
松耦合的本质
依赖接口而非实现类 + 容器注入:改变依赖实现(如 Axe 从 StoneAxe 换成 SteelAxe)只需改配置,调用者代码零改动。这就是「面向接口编程」+「依赖注入」带来的解耦收益。
常见误解(避坑)
- ❌ "IoC 和 DI 是一回事"。→ IoC 是思想,DI 是实现;还有 Service Locator 等其它 IoC 实现方式。
- ❌ "@Autowired 按名称注入"。→ 默认按类型(byType),只有多个同类型候选时才退化为按名称 + @Qualifier。
- ❌ "字段注入最方便,应该多用"。→ 字段注入依赖隐式、难测试、易造成循环依赖不可见,官方推荐构造器注入。
- ❌ "构造器注入和 setter 注入没区别"。→ setter 是先无参构造再注入(对象已创建、依赖可缺),构造器是创建即注入(依赖强必需)。
关联
- 原始资料:✅【02】Spring核心机制:依赖注入
- 容器机制:[Spring IOC容器初始化与循环依赖](./Spring IOC容器初始化与循环依赖)(refresh 12 步 + Bean 生命周期 + 三级缓存)
- 总览:Spring技术栈总览
- 域地图:A00-百科/Java后端/Java后端