Spring IOC 原理——从容器到 Bean 生命周期,别再“背诵式“理解了
📌 本文定位:把 Spring IOC(控制反转)这个最核心的概念讲透。不只会说"IOC 把控制权交给容器",要能画出 Bean 生命周期流程图、写出手动模拟 IOC 的 Demo、答上面试官的灵魂追问。
🎯 适合人群:
- 用了 Spring 很久但没搞懂"容器到底干了啥"的同学
- 面试被问 Bean 生命周期时支支吾吾的……就是你
- 想从"会用"进阶到"懂原理"的 Java 学习者
📑 目录
文章目录
1. 先搞懂三个词:IOC / DI / DL
面试常问:“说说你对 IOC 的理解。” 大部分人张口就背——“控制反转,把对象的创建权交给 Spring 容器。”
问题是,"控制"指什么?"反转"对比的是什么?
1.1 传统方式 vs IOC 方式
传统方式(主动创建):
public class UserService {
// 自己 new —— 我来控制对象的创建
private UserDao userDao = new UserDaoImpl();
private UserDao oracleDao = new OracleUserDaoImpl();
public void doSomething() {
userDao.save();
}
}
问题:UserService 和 UserDaoImpl 强耦合。想换 Oracle 实现?改代码。
IOC 方式(被动注入):
public class UserService {
// 我不 new 了,你(容器)给我
private UserDao userDao;
// 通过构造器/Setter 传入
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public void doSomething() {
userDao.save();
}
}
然后告诉容器:
<bean id="userDao" class="com.example.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.example.service.UserService">
<constructor-arg ref="userDao"/>
</bean>
或者用注解:
@Service
public class UserService {
@Autowired
private UserDao userDao;
}
1.2 一句话说清楚
| 概念 | 全称 | 一句话 |
|---|---|---|
| IOC | Inversion of Control | 控制反转——对象的创建权从"程序员手动 new"反转给"容器管理" |
| DI | Dependency Injection | 依赖注入——容器把对象需要的依赖(另一个对象)自动传给它 |
| DL | Dependency Lookup | 依赖查找——主动从容器里 getBean() 获取(用得少,不推荐) |
IOC 是设计思想,DI 是实现方式。 Spring 通过 DI 实现了 IOC。
1.3 传统 vs IOC 对比
┌────────────────────┐ ┌────────────────────┐
│ 传统方式 │ │ Spring IOC │
│ │ │ │
│ 你的代码 │ │ 你的代码 │
│ ├─ new A() │ │ ├─ @Autowired │
│ ├─ new B(A) │ │ └─ 等容器注入 │
│ └─ new C(B) │ │ │
│ │ │ ┌──────────┐ │
│ 你得自己管 │ │ │ IOC容器 │ │
│ 对象的创建 │ │ │ 创建→管理 │ │
│ 和生命周期 │ │ │ 注入→销毁 │ │
│ │ │ └──────────┘ │
│ 控制权:你 │ │ 控制权:容器 │
└────────────────────┘ └────────────────────┘
1.4 为什么要有 IOC?
- 解耦:不再
new()死一个实现类,换实现不换代码 - 方便测试:注入 Mock 对象
- 管理生命周期:单例、原型、作用域由容器统一管
- AOP 的基础:没有容器代理,AOP 切不进去
2. IOC 容器长什么样?
Spring 的 IOC 容器本质就是一个 大 Map。
// 极度简化的理解
public class SimpleIocContainer {
// key: beanName, value: bean 实例
private Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
public Object getBean(String name) {
return singletonObjects.get(name);
}
public void registerBean(String name, Object bean) {
singletonObjects.put(name, bean);
}
}
当然真实源码复杂得多,但核心思想就是:容器启动时扫描配置 → 创建 Bean → 放进 Map → 谁用谁取。
2.1 BeanFactory——老祖宗
public interface BeanFactory {
Object getBean(String name);
<T> T getBean(Class<T> requiredType);
boolean containsBean(String name);
boolean isSingleton(String name);
// ...
}
BeanFactory 是 IOC 容器的顶层接口,延迟加载——你调 getBean() 时才创建对象。
2.2 ApplicationContext——高级容器
public interface ApplicationContext extends BeanFactory {
// 继承了 BeanFactory,还多了:
// 国际化(MessageSource)
// 事件发布(ApplicationEventPublisher)
// 资源访问(ResourceLoader)
// 环境抽象(EnvironmentCapable)
}
ApplicationContext 在 启动时预加载所有单例 Bean(饿汉模式)。
| 特性 | BeanFactory | ApplicationContext |
|---|---|---|
| 加载策略 | 延迟加载(用到才创建) | 预加载(启动时创建所有单例) |
| 国际化 | ❌ | ✅ |
| 事件机制 | ❌ | ✅ |
| 自动注册 BeanPostProcessor | ❌(需手动) | ✅ |
| 常用实现类 | XmlBeanFactory(已废弃) |
ClassPathXmlApplicationContext、AnnotationConfigApplicationContext |
结论:日常开发直接用 ApplicationContext,几乎不用 BeanFactory。
2.3 主流实现类
// 1. 基于 XML(老项目)
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 基于注解配置(现代项目)
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
// 3. 基于 Spring Boot(默认)
// SpringApplication.run() 内部创建的就是 AnnotationConfigApplicationContext
3. 三种依赖注入方式详解
面试必问:Spring 有哪几种注入方式?推荐哪种?为什么?
3.1 构造器注入(✅ 推荐)
@Service
public class OrderService {
private final UserService userService;
private final ProductService productService;
// Spring 自动匹配参数,按类型注入
public OrderService(UserService userService, ProductService productService) {
this.userService = userService;
this.productService = productService;
}
}
优点:
- 不可变性:
final关键字,注入后不可修改 - 依赖完整性:构造时依赖必须全部就绪,不会出现 NPE
- 方便测试:直接
new OrderService(mockUserService, mockProductService),不需要反射
3.2 Setter 注入
@Service
public class OrderService {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}
特点:
- 可选依赖可以用 Setter
- 可以后续修改(不推荐)
- 对象创建后可能依赖还未注入
3.3 字段注入(❌ 不推荐)
@Service
public class OrderService {
@Autowired // 直接在字段上
private UserService userService;
@Autowired
private ProductService productService;
}
缺点:
- 无法用
final,对象可变 - 无法直接
new测试,必须依赖 Spring 容器或反射 - 隐藏了依赖关系,类看起来很"干净",但外部看不到它依赖什么
3.4 对比总结
| 维度 | 构造器注入 | Setter 注入 | 字段注入 |
|---|---|---|---|
| 不可变性 | ✅ 支持 final |
❌ | ❌ |
| 依赖完整性 | ✅ 必须完整 | ⚠️ 可能遗漏 | ⚠️ 可能遗漏 |
| 单元测试 | ✅ 直接 new | ✅ 直接 new | ❌ 需反射/Spring |
| 循环依赖解决 | ❌ 无法解决 | ✅ 可解决 | ✅ 可解决 |
| 官方推荐 | ✅ 强烈推荐 | 可选依赖可用 | ❌ 不推荐 |
💡 一句话:能用构造器就不要用字段注入。 Spring 官方在文档里明确推荐构造器注入。
4. Bean 生命周期——面试核心考点
这是面试最常考、也最能拉开差距的题。别只背那几个名字,要理解顺序和为什么。
4.1 完整生命周期流程图
┌────────────────────────────────────────────────────────────────────┐
│ Bean 完整生命周期(13 步) │
│ │
│ 1. 类加载 → 通过反射获取 Bean 的 Class 元信息 │
│ │ │
│ ▼ │
│ 2. 实例化 → 反射调用构造器创建原始对象 (new) │
│ │ │
│ ▼ │
│ 3. 属性赋值 → 填充 @Autowired、@Value、XML <property> 等 │
│ │ │
│ ▼ │
│ 4. Aware 接口回调 │
│ ├─ BeanNameAware.setBeanName() │
│ ├─ BeanClassLoaderAware.setBeanClassLoader() │
│ └─ BeanFactoryAware.setBeanFactory() │
│ │ │
│ ▼ │
│ 5. BeanPostProcessor#postProcessBeforeInitialization │
│ (初始化前处理,这里可以做代理、包装等) │
│ │ │
│ ▼ │
│ 6. InitializingBean#afterPropertiesSet() │
│ (或 @PostConstruct / init-method) │
│ │ │
│ ▼ │
│ 7. BeanPostProcessor#postProcessAfterInitialization │
│ (初始化后处理,⭐ AOP 动态代理就在这里生成!) │
│ │ │
│ ▼ │
│ 8. Bean 就绪 → 可以被注入到其他 Bean 中使用 │
│ │ │
│ ▼ │
│ 9. DisposableBean#destroy() │
│ (或 @PreDestroy / destroy-method) │
│ │ │
│ ▼ │
│ 10. 销毁 │
└────────────────────────────────────────────────────────────────────┘
4.2 步骤详解(按顺序)
① 实例化
调用构造器创建原始对象,此时属性全是默认值。
// 底层通过反射
Constructor<?> constructor = beanClass.getDeclaredConstructor();
Object bean = constructor.newInstance();
② 属性赋值
把配置的属性填充进去。
// 简化:遍历 @Autowired 字段,反射 set
Field field = beanClass.getDeclaredField("userService");
field.setAccessible(true);
field.set(bean, userServiceBean);
③ Aware 接口回调
如果 Bean 实现了 Aware 子接口,就把容器相关信息告诉它。
public class MyBean implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
}
④ BeanPostProcessor#postProcessBeforeInitialization
初始化之前的"预处理"机会。可以对 Bean 做包装、修改。
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof UserService) {
System.out.println("UserService 初始化前...");
}
return bean; // 可以返回包装后的对象
}
}
⑤ 初始化(InitializingBean / @PostConstruct / init-method)
@Component
public class MyBean implements InitializingBean {
@PostConstruct
public void init() {
System.out.println("@PostConstruct 执行");
}
@Override
public void afterPropertiesSet() {
System.out.println("InitializingBean.afterPropertiesSet() 执行");
}
}
执行顺序: @PostConstruct → InitializingBean.afterPropertiesSet() → init-method
⑥ BeanPostProcessor#postProcessAfterInitialization
⭐ 这是 AOP 动态代理生成的地方!
@Component
public class AopBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 如果有 @Transactional / @Aspect 注解,生成 JDK 动态代理或 CGLIB 代理
if (bean.getClass().isAnnotationPresent(Transactional.class)) {
return Proxy.newProxyInstance(/* ... */); // 返回代理对象
}
return bean;
}
}
⑦ Bean 就绪
Bean 正式放入 singletonObjects 这个 Map 中,供其他地方注入使用。
⑧ 销毁
容器关闭时调用。
@Component
public class MyBean implements DisposableBean {
@PreDestroy
public void preDestroy() {
System.out.println("@PreDestroy 执行");
}
@Override
public void destroy() {
System.out.println("DisposableBean.destroy() 执行");
}
}
4.3 关键源码入口
// AbstractAutowireCapableBeanFactory.java —— 核心方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 1. 实例化
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
// 2. 属性赋值
populateBean(beanName, mbd, instanceWrapper);
// 3. 初始化(包含 Aware + BeanPostProcessor + init)
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 3.1 调用 Aware 接口
invokeAwareMethods(beanName, bean);
// 3.2 BeanPostProcessor before
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 3.3 执行初始化
invokeInitMethods(beanName, wrappedBean, mbd);
// 3.4 BeanPostProcessor after(AOP 代理在这里)
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
5. 循环依赖——三级缓存怎么解决?
5.1 什么是循环依赖?
@Service
public class AService {
@Autowired
private BService bService; // A 依赖 B
}
@Service
public class BService {
@Autowired
private AService aService; // B 依赖 A
}
你 new A,A 要 B,new B,B 要 A——死循环。
5.2 Spring 的三级缓存
public class DefaultSingletonBeanRegistry {
/** 一级缓存:singletonObjects —— 完全创建好的 Bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 二级缓存:earlySingletonObjects —— 早期暴露的 Bean(刚实例化,未完成属性赋值) */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** 三级缓存:singletonFactories —— 存放 ObjectFactory,用来生成早期暴露的 Bean */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
}
5.3 解决流程(以 A → B → A 为例)
时间线 ↓
1. getBean("a")
├─ 实例化 A(new AService())→ 原始对象
├─ 把 A 放入三级缓存:singletonFactories.put("a", () -> getEarlyBeanReference("a"))
├─ 开始属性赋值 → 发现需要 B
│
├─ 2. getBean("b")
│ ├─ 实例化 B(new BService())→ 原始对象
│ ├─ 把 B 放入三级缓存
│ ├─ 开始属性赋值 → 发现需要 A
│ │
│ ├─ 3. getBean("a") 再次
│ │ ├─ 一级缓存 singletonObjects 没有 A(还没放)
│ │ ├─ 二级缓存 earlySingletonObjects 没有 A(还没放)
│ │ ├─ 三级缓存 singletonFactories 有 A!
│ │ ├─ 拿到 A 的 ObjectFactory,执行 getObject() 得到早期 A
│ │ ├─ 把早期 A 提升到二级缓存 earlySingletonObjects
│ │ └─ 返回早期 A 给 B
│ │
│ └─ B 拿到 A 的引用,完成属性赋值
│ └─ B 走完完整生命周期 → 放入一级缓存 singletonObjects
│
└─ A 拿到 B(已完成),继续完成属性赋值
└─ A 走完完整生命周期 → 放入一级缓存 singletonObjects
└─ 清理 A 在二级、三级缓存的记录
5.4 关键结论
| 问题 | 答案 |
|---|---|
| 三级缓存解决了什么? | 让未完成初始化的 Bean 提前暴露给其他 Bean 引用 |
| 为什么要三级?二级不行? | 三级缓存存的是 ObjectFactory,可以在提前暴露时执行 AOP 增强。如果直接用二级存原始对象,AOP 代理就丢了 |
| 构造器注入能解决循环依赖吗? | ❌ 不能! 构造器注入在实例化阶段就要求参数就绪,那时三级缓存还没放东西 |
| 原型作用域能解决吗? | ❌ 不能! 原型 Bean 不缓存,每次都新创建 |
💡 面试高频题:你遇到过循环依赖吗?怎么解决的?
回答策略:先解释什么是循环依赖 → Spring 三级缓存机制 → 然后说实际开发中应该通过重构代码避免循环依赖,而不是依赖三级缓存。可以提取公共依赖、改用构造器注入(构造器注入报错能提前发现问题)。
6. 手写一个微型 IOC 容器
理解了原理,写个超简版感受一下:
6.1 定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {
String value() default "";
}
@Target({ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAutowired {
}
6.2 手写 IOC 容器
public class MyApplicationContext {
// 一级缓存:存放所有 Bean 实例
private final Map<String, Object> beanMap = new ConcurrentHashMap<>();
public MyApplicationContext(String basePackage) {
// 1. 扫描包下所有带 @MyComponent 的类
Set<Class<?>> classes = scanPackage(basePackage);
// 2. 实例化所有 Bean(放入 map)
for (Class<?> clazz : classes) {
String beanName = getBeanName(clazz);
beanMap.put(beanName, clazz.getDeclaredConstructor().newInstance());
}
// 3. 执行依赖注入
for (Class<?> clazz : classes) {
String beanName = getBeanName(clazz);
Object bean = beanMap.get(beanName);
injectDependencies(bean, clazz);
}
}
private Set<Class<?>> scanPackage(String basePackage) {
// 实际项目中用 ClassPathScanningCandidateComponentProvider
// 这里为简化,手动注册
Set<Class<?>> classes = new HashSet<>();
// ... 扫描逻辑(略,详见下文 Demo)
return classes;
}
private void injectDependencies(Object bean, Class<?> clazz) throws Exception {
// 遍历所有字段,找 @MyAutowired
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(MyAutowired.class)) {
Object dependency = beanMap.get(field.getName());
field.setAccessible(true);
field.set(bean, dependency);
}
}
}
private String getBeanName(Class<?> clazz) {
MyComponent component = clazz.getAnnotation(MyComponent.class);
String value = component.value();
if (value.isEmpty()) {
// 默认:首字母小写的类名
String simpleName = clazz.getSimpleName();
return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
}
return value;
}
@SuppressWarnings("unchecked")
public <T> T getBean(String name) {
return (T) beanMap.get(name);
}
}
6.3 测试
@MyComponent
public class UserDao {
public void save() {
System.out.println("保存用户...");
}
}
@MyComponent
public class UserService {
@MyAutowired
private UserDao userDao;
public void doSomething() {
userDao.save();
}
}
// 运行
public class Main {
public static void main(String[] args) {
MyApplicationContext ctx = new MyApplicationContext("com.example");
UserService userService = ctx.getBean("userService");
userService.doSomething(); // 输出:保存用户...
}
}
虽然只有几十行,但已经包含了 IOC 容器的核心逻辑:扫描 → 实例化 → 注入 → 使用。
7. Bean 的作用域
@Component
@Scope("singleton") // 默认值,可以省略
public class UserService { }
@Component
@Scope("prototype")
public class OrderService { }
| 作用域 | 说明 | 适用场景 |
|---|---|---|
| singleton(默认) | 整个容器只有一个实例 | 无状态 Bean(Service、DAO) |
| prototype | 每次 getBean() 都创建新实例 | 有状态 Bean |
| request | 每个 HTTP 请求一个实例 | Web 应用 |
| session | 每个 HTTP Session 一个实例 | Web 应用 |
| application | 每个 ServletContext 一个实例 | Web 应用 |
8. @Component vs @Bean
面试也爱问这个区别:
| 维度 | @Component |
@Bean |
|---|---|---|
| 使用位置 | 类级别 | 方法级别(在 @Configuration 类中) |
| 谁写的类 | 你自己的类 | 第三方类(你改不了源码) |
| 创建方式 | 框架自动实例化 | 你自己写 new 逻辑 |
| 典型场景 | UserService、UserDao |
RestTemplate、DataSource、RedisTemplate |
// @Component 用在自己的类上
@Component
public class UserService { }
// @Bean 用在第三方类上
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
9. 面试高频问答
Q1:IOC 是什么?有什么好处?
答:IOC(控制反转)是一种设计思想,将对象的创建、组装和管理控制权从程序代码转移到 IOC 容器。好处:
- 解耦:组件之间通过接口交互,不依赖具体实现
- 可测试性:可以注入 Mock 对象进行单元测试
- 统一管理:对象的生命周期(创建 → 初始化 → 销毁)由容器统一管理
- AOP 的基础:没有容器代理,AOP 切不进去
Q2:依赖注入有哪几种方式?Spring 推荐哪种?
答:三种方式:
- 构造器注入(✅ 推荐):依赖不可变、注入完整、方便测试。Spring 官方推荐
- Setter 注入:适合可选依赖,但对象可能不完整
- 字段注入(❌ 不推荐):代码最简洁,但无法用 final,无法直接 new 测试,隐藏了依赖关系
Q3:Bean 的生命周期能不能说一遍?
答:分 8 个阶段(从简单到详细):
① 实例化:反射调用构造器创建原始对象
② 属性赋值:填充 @Autowired、@Value
③ Aware 回调:调用 BeanNameAware、BeanFactoryAware 等
④ BeanPostProcessor#before:初始化前处理
⑤ 初始化:@PostConstruct → InitializingBean → init-method
⑥ BeanPostProcessor#after:⭐ AOP 代理在这里生成
⑦ 就绪使用:放入容器,供注入
⑧ 销毁:@PreDestroy → DisposableBean → destroy-method关键源码入口在
AbstractAutowireCapableBeanFactory.doCreateBean()和initializeBean()方法。
Q4:三级缓存解决循环依赖的原理?
答:Spring 通过三级缓存(
singletonObjects/earlySingletonObjects/singletonFactories)解决单例 setter 注入的循环依赖。核心思路:先实例化,暴露早期引用,再填充属性。
A 实例化后放入三级缓存(ObjectFactory),填充属性时发现需要 B → 去创建 B → B 填充属性时需要 A → 从三级缓存拿到 A 的早期引用 → B 完成创建 → A 拿到完整的 B → A 完成创建。
注意:构造器注入和 prototype 作用域无法解决循环依赖。
Q5:@Component 和 @Bean 的区别?
答:
@Component用于类级别,框架自动扫描实例化,适用于自己写的类@Bean用于 @Configuration 类中的方法,需要手动 new,适用于第三方类(如 DataSource、RestTemplate)简单说:自己的类用 @Component,第三方的类用 @Bean。
Q6:BeanFactory 和 ApplicationContext 有什么区别?
答:
- 加载策略:BeanFactory 延迟加载,ApplicationContext 预加载所有单例
- 功能扩展:ApplicationContext 继承了 BeanFactory,还多了国际化、事件发布、资源访问、Environment 抽象
- 自动注册:ApplicationContext 自动注册 BeanPostProcessor 和 BeanFactoryPostProcessor,BeanFactory 需要手动
日常开发直接用 ApplicationContext。
Q7:singleton Bean 是线程安全的吗?
答:不是天生的。单例意味着多个线程共享同一个 Bean 实例,如果 Bean 中有可变状态(实例变量),就可能出现线程安全问题。
解决方式:
- 无状态设计(推荐):Service 层方法只操作局部变量 + 参数,不保存实例变量
- ThreadLocal:如
SimpleDateFormat的线程安全问题- 加锁:
synchronized或Lock(不推荐,影响性能)
Q8:Spring 是怎么管理 Bean 的单例的?
答:实际上就是 ConcurrentHashMap。
在
DefaultSingletonBeanRegistry中,维护了一个Map<String, Object> singletonObjects。Bean 创建完成后就 put 进去,getBean 时先从 map 取,取不到才创建。线程安全通过synchronized块 +ConcurrentHashMap保证。
10. 总结 + 推荐阅读
核心一句话
Spring IOC = 容器接管对象的全生命周期(创建 → 注入 → 初始化 → 销毁),你只需要关注业务逻辑。
知识点脑图
Spring IOC 原理
├── IOC 概念
│ ├── 控制反转:创建权交给容器
│ ├── 依赖注入:容器自动注入依赖
│ └── 好处:解耦、可测试、统一管理
├── IOC 容器
│ ├── BeanFactory(延迟加载)
│ └── ApplicationContext(预加载)
├── 依赖注入方式
│ ├── 构造器注入 ✅
│ ├── Setter 注入
│ └── 字段注入 ❌
├── Bean 生命周期(8 步)
│ ├── 实例化 → 属性赋值 → Aware → Before → init → After → 就绪 → 销毁
│ └── 关键:BeanPostProcessor#after → AOP 代理
├── 循环依赖(三级缓存)
│ ├── 一级:完整 Bean
│ ├── 二级:早期 Bean
│ └── 三级:ObjectFactory
└── 作用域
├── singleton(默认)
├── prototype
└── request / session / application
推荐源码阅读路径
去 IDE 里 Debug 跟踪一遍,比看 10 篇文章都管用:
// 入口:随便写一个 @Component,断点打在以下方法
AbstractApplicationContext.refresh() // 容器启动
→ finishBeanFactoryInitialization() // 初始化所有单例 Bean
→ DefaultListableBeanFactory.preInstantiateSingletons()
→ AbstractBeanFactory.getBean()
→ AbstractAutowireCapableBeanFactory.doCreateBean() // ⭐ 核心
→ createBeanInstance() // ① 实例化
→ populateBean() // ② 属性赋值
→ initializeBean() // ③ 初始化(含 BeanPostProcessor)
| 推荐阅读的类/方法 | 关注点 |
|---|---|
AbstractAutowireCapableBeanFactory.doCreateBean() |
Bean 创建的完整流程 |
AbstractAutowireCapableBeanFactory.populateBean() |
属性如何注入 |
AbstractAutowireCapableBeanFactory.initializeBean() |
Aware → Before → Init → After |
DefaultSingletonBeanRegistry.getSingleton() |
三级缓存获取逻辑 |
DefaultSingletonBeanRegistry.addSingletonFactory() |
三级缓存注册逻辑 |
💡 Debug 技巧:写一个最简单的
@Service+@Autowired项目,在doCreateBean()打上断点,按 F7 一步步跟踪,看着 Bean 从无到有、从原始对象到 AOP 代理的完整过程——这种体验是任何文字都无法替代的。
📌 写在最后:IOC 是 Spring 的基石,搞懂它之后 Spring AOP、事务管理、源码阅读都会豁然开朗。建议你把第 6 节的 手写 IOC 容器 自己敲一遍,再配合源码 Debug 跟踪一次,面试问 IOC 你就能碾压 90% 的人。
如果本文对你有帮助,欢迎点赞 👍 收藏 ⭐ 评论 💬,你的支持是我继续写学习笔记的最大动力!
更多推荐




所有评论(0)