适用读者:会用
@Autowired但说不清"对象到底谁创建的"的人。本系列第一篇。
前置:S04 ✅、S06 ✅。
实测环境:Spring Boot 3.3.6 / JDK 17(最小应用启动,2026-11-05)。
覆盖旧文:1556(586) 1134(261) 1557(234) 1742(219) 969(82) 963(87) 2642(61) 1133(0) = 1,530 点。
覆盖扩展:E-S07-001(IoC 与 DI 的区别)、E-S07-002(BeanDefinition 与启动)。
下一篇:S07-B02 · Bean 生命周期与作用域。
1. 一句话结论
IoC 是"控制权反转"(对象创建权从你的代码交给容器),DI 是"实现手段"(容器把依赖注入进来)。Spring 容器 = BeanDefinition 注册表 + 实例缓存 + 生命周期管理。
2. IoC 与 DI 不是同义词(E-S07-001)
| 概念 | 说明 |
|---|---|
| IoC(控制反转) | 设计原则:谁创建对象、谁决定依赖,从"我"变成"容器" |
| DI(依赖注入) | 实现方式:构造器/Setter/字段注入 |
| 容器 | 承载 Bean 的运行时(ApplicationContext) |
判据:"我还在 new 服务类吗?" 在 → 没用 IoC;不在 → 已在用。
实测(最小 Boot 应用):
2026-11-05 ... Tomcat started on port 19070 (http) with context path '/'
2026-11-05 ... Started App in 8.281 seconds (process running for 10.181)
"Started in 8.281 seconds"里的时间,几乎全花在"扫描 + 创建 Bean + 启动容器"上——这就是容器在干活的证据。
3. Bean 从哪来:三种注册方式(A-963)
| 方式 | 写法 | 适用 |
|---|---|---|
| 组件扫描 | @Component/@Service/@Repository |
自己写的类 |
配置类 @Bean |
@Configuration + @Bean 方法 |
第三方类、需要构造逻辑 |
| 手动注册 | ApplicationContext.registerBean(...) / BeanDefinitionRegistry |
动态/框架层 |
@Bean 与 @Component 的区别:
| 维度 | @Component |
@Bean |
|---|---|---|
| 位置 | 类上 | 方法上 |
| 谁能用 | 自己写的类 | 任何类(含 jar 里的) |
| 创建控制 | 容器反射调用构造器 | 你写方法体(可加逻辑) |
判据:"这个类我能改吗?" 能 → @Component;不能(第三方库)→ @Bean。
4. 容器启动做了什么(E-S07-002)
① 读取配置(注解扫描 / XML / 配置类)
② 生成 BeanDefinition(描述"怎么造")
③ BeanFactoryPostProcessor(改定义,如占位符替换)
④ 实例化 Bean(按依赖顺序)
⑤ BeanPostProcessor(AOP 代理在这里织入)
⑥ 发布 ContextRefreshedEvent
| 阶段 | 你能插手的地方 |
|---|---|
| ② | @ComponentScan 范围、@Conditional |
| ③ | BeanFactoryPostProcessor |
| ⑤ | BeanPostProcessor(AOP/自定义增强) |
5. @Autowired 的三种注入
| 方式 | 写法 | 评价 |
|---|---|---|
| 构造器 | public XxxService(Repo r) |
推荐(依赖明确、易测试、可 final) |
| Setter | @Autowired setX(...) |
可选依赖 |
| 字段 | @Autowired private Repo r |
不推荐(难测试、掩盖依赖过多) |
判据:"这个类依赖超过 5 个对象吗?" 是 → 先怀疑设计,而不是换注入方式。
6. 五个误区
| 误区 | 真相 |
|---|---|
| "IoC 就是 DI" | IoC 是原则,DI 是实现 |
"@Component 能加在任何类上" |
只能加在自己能改的类;第三方类用 @Bean |
| "字段注入更方便所以更好" | 隐藏依赖、难单测 |
| "容器启动慢是框架问题" | 大量 Bean/扫描范围过大是常见原因 |
| "Bean 就是单例对象" | 默认单例,但作用域可配(B02) |
7. 自检
- IoC 与 DI 的区别?用一句话各说清。
@Component与@Bean怎么选?- 容器启动六个阶段里,哪一步织入 AOP?
- 为什么推荐构造器注入?
- "Started in 8.281s" 这段时间花在哪?
8. 下一篇
S07-B02 · Bean 生命周期与作用域
容器讲完,下一篇跟踪一个 Bean 的一生:构造 → 注入 → @PostConstruct → afterPropertiesSet → 使用 → @PreDestroy(全部实测)。
本篇属于系列《S07 · Spring 框架》。旧文来源:A-1556/1134/1557/1742/969/963/2642/1133;扩展点 E-S07-001/002。启动耗时与端口为 Spring Boot 3.3.6 实测。