---
title: Spring IoC 核心：循环依赖、注解体系与 Bean 生命周期
type: concept
domain: spring
tags: [spring, ioc, circular-dependency, annotation, bean-lifecycle, three-level-cache]
status: learning
created: 2026-09-28
last_reviewed: 2026-09-28
method: feynman
related_questions:
  - "什么是 Spring 的循环依赖问题？"
  - "Spring 中 @Service、@Component、@Repository 等注解区别是什么？"
  - "Spring Bean 的生命周期是怎么样的？"
related_knowledge: []
visualizations: []
anki_cards: 8
interview_rounds:
  - "2026-09-28-round-1"
---

# Spring IoC 核心：循环依赖、注解体系与 Bean 生命周期

> Spring IoC 容器的三大核心机制：三级缓存解决循环依赖、五大注解的语义分层、Bean 生命周期的完整骨架

## TL;DR（3-5 句话，面试前 30 秒扫完）

- **循环依赖**：A→B→A 互相引用，Spring 通过**三级缓存**（L1 成品 / L2 半成品 / L3 ObjectFactory）解决，但**构造器注入无法解决**
- **注解体系**：5 个组件注解（@Component / @Service / @Repository / @Controller / @RestController）元注解都是 @Component，核心差异在**语义分层**和**@Repository 的异常转换**
- **Bean 生命周期**：5 阶段（BeanDefinition 加载 → 实例化 → 属性填充 → 初始化 → 销毁）+ 3 类核心回调（BeanPostProcessor / Aware / InitializingBean）

## 关键结论

- **结论 A（循环依赖）**：Spring 默认通过三级缓存解决单例 Bean 的循环依赖，但**构造器注入无法解决**（因为构造器执行时 Bean 尚未创建完成）
- **结论 B（注解体系）**：@Repository 的核心差异是**自动启用异常转换**（PersistenceExceptionTranslationPostProcessor，SQLException→DataAccessException），@RestController = @Controller + @ResponseBody
- **结论 C（Bean 生命周期）**：核心骨架 = 实例化→放 L3→属性填充→Aware→beforeInit→@PostConstruct→afterPropertiesSet→initMethod→afterInit(AOP 代理)→放 L1→使用→@PreDestroy→destroy→destroyMethod
- **结论 D（工程实践）**：循环依赖本质是**设计问题**，应通过 @Lazy / 拆 Bean / 事件解耦规避，而非依赖三级缓存

## 完整讲解（费曼四步）

### STEP 1 · 概念（一句话定义）

- **循环依赖**：两个或多个 Bean 在初始化过程中互相需要对方，导致 Spring 无法按顺序创建它们
- **注解体系**：Spring 通过 5 个组件注解标注 Bean 的语义分层，底层元注解都是 @Component
- **Bean 生命周期**：Spring 容器从 BeanDefinition 加载到 Bean 销毁的完整流程，包含实例化、属性填充、初始化、使用、销毁五个阶段

### STEP 2 · 大白话（生活类比）

> **类比 1（循环依赖）**：就像你和朋友互相借钱——你要借钱给他，他也想借钱给你，但谁都没有本金。Spring 的三级缓存就像"先给你一张欠条（L3），等对方还钱后再换成现金（L1）"。

> **类比 2（注解体系）**：就像公司里的岗位标签——程序员（@Component）、架构师（@Service）、DBA（@Repository）、前台（@Controller），本质都是员工（@Component），但不同标签有不同的职责和权限。

> **类比 3（Bean 生命周期）**：就像员工的入职流程——签合同（实例化）→ 分配工位（属性填充）→ 培训（初始化）→ 工作（使用）→ 离职（销毁），每个环节都有 HR（Spring 容器）介入。

### STEP 3 · 底层（细节 + 代码/表格）

#### 3.1 循环依赖的三级缓存机制

| 缓存层级 | 存储内容 | 生命周期 |
|---------|---------|---------|
| **L1（singletonObjects）** | 完全初始化好的成品 Bean | 初始化完成后放入，使用阶段读取 |
| **L2（earlySingletonObjects）** | 半成品 Bean（已完成实例化，可被代理） | 实例化后放入，初始化完成后移除 |
| **L3（singletonFactories）** | ObjectFactory（Bean 的工厂对象） | 实例化后放入，初始化完成后移除 |

**触发链**：
```
A 实例化 → 放 L3 → A 属性填充 → 发现需要 B
  → B 实例化 → 放 L3 → B 属性填充 → 发现需要 A
    → 从 L3 拿 A 的 ObjectFactory → getEarlyBeanReference() → 放 L2
  → B 初始化完成 → 放 L1
→ A 从 L2 拿 B → A 初始化完成 → 放 L1
```

**关键限制**：
- **构造器注入无法解决**：构造器执行时 Bean 尚未创建完成，无法放入 L3
- **Spring Boot 2.6+ 默认禁止**：`spring.main.allow-circular-references=false`

**规避方案**：
1. `@Lazy`：延迟初始化，避免启动时触发循环依赖
2. 拆 Bean：将循环依赖的部分摘出去，放到独立的位置
3. 事件解耦：用 Spring Event 替代直接的依赖注入

#### 3.2 五大注解的完整差异

| 注解 | 元注解 | 核心差异 | 典型场景 |
|------|-------|---------|---------|
| @Component | 无 | 通用 Bean 标注 | 通用组件 |
| @Service | @Component | 纯语义标注 | 业务逻辑层 |
| @Repository | @Component | **自动启用异常转换**（PersistenceExceptionTranslationPostProcessor） | DAO 层，SQLException→DataAccessException |
| @Controller | @Component | 处理 Web 请求，返回 View 名称 | 传统 Web 应用 |
| @RestController | @Controller | @Controller + @ResponseBody，直接返回 JSON | RESTful API |

**@Repository 的核心差异**：
```java
// @Repository 自动启用异常转换
@Transactional
@Repository
public class UserDao {
    public User findById(Long id) {
        // SQLException 会自动转换为 DataAccessException
        return jdbcTemplate.queryForObject(...);
    }
}
```

#### 3.3 Bean 生命周期的完整骨架

**5 阶段**：
1. **BeanDefinition 加载**：从 XML / JavaConfig / 注解扫描加载元数据
2. **实例化**：调用无参构造器创建 Bean 实例，**放入 L3**
3. **属性填充**：依赖注入（@Autowired / @Value），**可能从 L2/L3 取代理**
4. **初始化**：
   - Aware 回调（BeanNameAware / BeanFactoryAware / ApplicationContextAware）
   - BeanPostProcessor.postProcessBeforeInitialization()
   - 初始化方法（@PostConstruct → afterPropertiesSet → init-method）
   - BeanPostProcessor.postProcessAfterInitialization()（**AOP 代理生成**）
   - **放入 L1**
5. **使用**：从 L1 读取成品 Bean
6. **销毁**：@PreDestroy → destroy → destroy-method

**3 类核心回调**：
| 回调类型 | 调用时机 | 典型用途 |
|---------|---------|---------|
| BeanPostProcessor | 初始化前后 | AOP 代理、异步支持 |
| Aware | 初始化前 | 获取容器引用（ApplicationContext 等） |
| InitializingBean / @PostConstruct | 初始化阶段 | 自定义初始化逻辑 |

### STEP 4 · 简化（比喻/口诀）

> **循环依赖口诀**：L3 放工厂，L2 放代理，L1 放成品；构造器注入解不了，@Lazy 拆 Bean 事件解耦。

> **注解体系口诀**：@Component 是爹，@Service 是业务，@Repository 管异常，@Controller 管 Web，@RestController 出 JSON。

> **Bean 生命周期口诀**：加载→实例化→填属性→初始化→使用→销毁；三兄弟顺序：@PostConstruct → afterPropertiesSet → initMethod。

## 常见误区（从面试记录提炼）

- **误区 1（循环依赖）**："构造器注入也能解决循环依赖" → 正确说法：**构造器注入无法解决**（构造器执行时 Bean 尚未创建完成，无法放入 L3）
- **误区 2（注解体系）**："@Service 和 @Component 没区别" → 正确说法：元注解相同，但**语义分层不同**；@Repository 有异常转换，@Controller 处理 Web 请求
- **误区 3（Bean 生命周期）**："Spring Bean 的生命周期就是实例化→使用→销毁" → 正确说法：**5 阶段 + 3 类核心回调**，包括 BeanDefinition 加载、属性填充、初始化（三兄弟顺序）
- **误区 4（工程实践）**："循环依赖是 Spring 的 Bug" → 正确说法：**循环依赖本质是设计问题**，应通过 @Lazy / 拆 Bean / 事件解耦规避

## 延伸追问（面试追问预演）

1. **追问 A**：三级缓存为什么需要第三级？
   - 要点：L3 存储 ObjectFactory，用于**延迟生成代理**（如果 Bean 需要 AOP 代理，L3 的 ObjectFactory 会在需要时生成代理，而不是直接返回原始 Bean）

2. **追问 B**：@Repository 的异常转换是怎么实现的？
   - 要点：通过 `PersistenceExceptionTranslationPostProcessor`（BeanPostProcessor）自动注册，将 SQLException 转换为 DataAccessException

3. **追问 C**：Bean 生命周期的初始化三兄弟顺序是什么？
   - 要点：@PostConstruct → afterPropertiesSet → init-method（销毁顺序相反）

4. **追问 D**：Spring Boot 2.6+ 为什么默认禁止循环依赖？
   - 要点：因为循环依赖本质是设计问题，Spring 团队鼓励通过更好的设计（@Lazy / 拆 Bean）解决，而非依赖框架的 workaround

## 速查表（面试前 30 秒扫完）

```
循环依赖 · 三级缓存（L1 成品/L2 代理/L3 工厂）· 构造器注入解不了 · @Lazy 拆 Bean 事件解耦
注解体系 · @Component 是爹 · @Service 业务 · @Repository 异常转换 · @Controller Web · @RestController JSON
Bean 生命周期 · 5 阶段（加载→实例化→填属性→初始化→销毁）· 3 类回调（BPP/Aware/InitializingBean）· 三兄弟顺序（@PostConstruct→afterPropertiesSet→initMethod）
常见错点：构造器注入能解循环依赖 ❌ / @Service 和 @Component 没区别 ❌ / 生命周期只有实例化→使用→销毁 ❌
```

## 关联题目（题库）

- [ ] 《什么是 Spring 的循环依赖问题？》—— 2026-09-28 Round 1, 评分 ⭐⭐⭐⭐
- [ ] 《Spring 中 @Service、@Component、@Repository 等注解区别是什么？》—— 2026-09-28 Round 1, 评分 ⭐⭐⭐
- [ ] 《Spring Bean 的生命周期是怎么样的？》—— 2026-09-28 Round 1, 评分 ⭐⭐⭐

## 关联知识

- [Spring AOP 核心](./spring-aop-core.md)
- [Spring 事务核心](./spring-transaction-core.md)

## Anki 候选卡片

以下知识点适合做 Anki 卡片：

1. **正**：Spring 三级缓存的三层分别存储什么？**反**：L1 成品 Bean / L2 半成品 Bean（可代理）/ L3 ObjectFactory（工厂对象）
2. **正**：为什么构造器注入无法解决循环依赖？**反**：构造器执行时 Bean 尚未创建完成，无法放入 L3
3. **正**：@Repository 的核心差异是什么？**反**：自动启用异常转换（PersistenceExceptionTranslationPostProcessor，SQLException→DataAccessException）
4. **正**：Spring Bean 生命周期的 5 阶段是什么？**反**：BeanDefinition 加载 → 实例化 → 属性填充 → 初始化 → 销毁
5. **正**：Bean 生命周期的 3 类核心回调是什么？**反**：BeanPostProcessor / Aware / InitializingBean
6. **正**：初始化三兄弟的顺序是什么？**反**：@PostConstruct → afterPropertiesSet → init-method
7. **正**：Spring Boot 2.6+ 为什么默认禁止循环依赖？**反**：循环依赖本质是设计问题，应通过 @Lazy / 拆 Bean / 事件解耦规避
8. **正**：Spring 解决循环依赖的 3 种规避方案是什么？**反**：@Lazy / 拆 Bean / 事件解耦

---

*最后更新：2026-09-28*
