@Autowired 和“依赖注入”的关系,就像“插头”和“用电”的关系。
“依赖注入”是什么?
依赖注入 (Dependency Injection, DI) 是一种设计模式和原则。
它的核心思想是:一个组件(对象)不应该自己去创建它所依赖的另一个组件,而应该由外部的“某人”(IoC 容器)把这个依赖“送”给它。
- 目标 (What):实现解耦,让组件只关注自己的业务,不关心依赖从哪来。
- 角色 (Who):
- 依赖方:需要别人帮助的组件(比如
MyController)。 - 被依赖方:提供帮助的组件(比如
MyService)。 - 注入者:负责协调和执行注入动作的“某人”(Spring IoC 容器)。
- 依赖方:需要别人帮助的组件(比如
依赖注入是一种行为,一个过程。
@Autowired 关键字做了什么?
@Autowired 是一个注解,它是一种指令或标记。
它的作用是告诉 Spring IoC 容器:“嘿!我(这个类)需要一个依赖,请在运行时把一个合适的 Bean 注入到这个位置!”
- 目标 (What):向 Spring 容器发出一个“自动装配”的请求。
- 角色 (Who):
- 标记位置:你可以把它放在字段、构造函数或 Setter 方法上,指定注入点。
- 执行者:Spring IoC 容器里的一个特殊组件(
AutowiredAnnotationBeanPostProcessor)会去寻找并处理这个注解。
@Autowired 是触发依赖注入这个行为的开关或扳机。
@Autowired 与“依赖注入”的关系
@Autowired 是实现“依赖注入”的一种具体方式。
让我们用一个生动的比喻来理解:
- 依赖注入 (DI):就像是“家用电器需要用电”这个概念。
- Spring IoC 容器:是整个城市的电网系统。
- 你的 Bean (
@Service,@Component等):是电网里的各种电器,比如电视机、冰箱。 @Autowired:就是你在墙上安装的那个电源插座。
整个流程是这样的:
- 声明需求:你在你的
MyController类(电视机)的myService字段(电源线)上加了@Autowired注解。这等于你对电工(Spring 容器)说:“我这台电视机需要电,请在这里给我留一个插座!” - 容器准备:Spring 容器在启动时,会创建并管理好所有的 Bean(电网里已经有了稳定的电力供应,并且知道每个电器的位置)。
- 执行注入:当 Spring 容器创建
MyController这个 Bean 时,它会检查这个类。- 它看到了
@Autowired这个“插座”。 - 它会根据
myService字段的类型(MyService.class)去电网(IoC 容器)里寻找一个匹配的 Bean(寻找可用的电源)。 - 找到后,它就把
MyService的实例注入(赋值)给myService字段。这个动作就像把电视机的插头插进插座里。
- 它看到了
所以,它们的关系是:
- DI 是一个宏观的模式(我要用电)。
@Autowired是一个微观的实现工具(我需要一个插座来用电)。
@Autowired 的三种注入方式(三种“插座”的位置)
@Autowired 可以放在三个不同的地方,Spring 官方最推荐构造函数注入。
1. 字段注入 (Field Injection) - 【最简洁,但不推荐】
@RestController
public class MyController {
@Autowired
private MyService myService; // 直接在字段上加注解
// ...
}
- 优点:代码最少,看起来最干净。
- 缺点:
- 可测试性差:在单元测试中,你无法在不启动 Spring 的情况下,轻松地为
myService设置一个 Mock 对象。 - 隐藏依赖:依赖关系被隐藏在类的内部,不够清晰。
- 可能导致循环依赖:这种方式更容易写出循环依赖的代码。
- 可测试性差:在单元测试中,你无法在不启动 Spring 的情况下,轻松地为
2. Setter 方法注入 (Setter Injection) - 【较少使用】
@RestController
public class MyController {
private MyService myService;
@Autowired
public void setMyService(MyService myService) { // 在Setter方法上加注解
this.myService = myService;
}
// ...
}
- 优点:允许注入可选的依赖(如果
myService不是必须的)。 - 缺点:对象在创建后,其依赖关系可能被改变,违反了“不变性”原则。
3. 构造函数注入 (Constructor Injection) - 【官方推荐】
@RestController
public class MyController {
private final MyService myService; // 可以声明为 final,确保不变性
// 在构造函数上加注解
// 在只有一个构造函数的情况下,@Autowired 注解可以省略
@Autowired
public MyController(MyService myService) {
this.myService = myService;
}
// ...
}
- 优点:
- 依赖清晰:所有必需的依赖都在构造函数中一目了然。
- 保证不变性:依赖可以被声明为
final,一旦注入就不会被改变,保证了线程安全。 - 保证对象可用性:对象一旦被创建,它所必需的依赖就已经准备就绪,不会出现
NullPointerException。 - 极佳的可测试性:在单元测试中,你可以非常简单地
new MyController(new MockMyService()),完全不需要 Spring 容器的介入。
总结
| 概念 | 角色 | 描述 |
|---|---|---|
| 依赖注入 (DI) | 设计模式/原则 | 一种思想:组件的依赖由外部容器来提供,以实现解耦。 |
@Autowired | 注解/指令 | Spring 框架中实现 DI 的一种工具,它告诉容器“请在这里注入一个 Bean”。 |
@Autowired 是你向 Spring 发出的一个请求,而 Spring 响应这个请求并为你完成依赖的传递,这个过程就是依赖注入。
1702



被折叠的 条评论
为什么被折叠?



