一、Bean 加载只干三件事
其实 Bean 的加载只做了三件事,解析 → 注册 → 实例化;
- 解析配置: 无论 XML、注解还是 JavaConfig,本质都是把
<bean>
或@Component
之类的信息解析成BeanDefinition
。 - 注册元数据:
BeanDefinition
统一塞进BeanDefinitionRegistry
(默认实现是DefaultListableBeanFactory
)。 - 实例化 & 依赖注入: 真正 new 出对象,填充属性,执行各种回调,最后放进单例池。
二、refresh() 时序图
refresh()
几乎囊括了 IoC 全部门道,后面几段都从这里往下钻。接下来,我们通俗的解释一下,究竟都做了什么。
- refresh() 负责容器生命周期的「自举」。
- prepareRefresh() 校验环境、初始化属性占位符。
- obtainFreshBeanFactory() 创建或刷新 DefaultListableBeanFactory,确保是干净的工厂实例。
- prepareBeanFactory() 给工厂塞基础组件(如 Environment、SystemProperties 等)、注册内置 BeanPostProcessor。
- postProcessBeanFactory() 是模板方法,留给 AbstractApplicationContext 的子类做额外处理。
- invokeBeanFactoryPostProcessors() → 修改/新增 BeanDefinition。
- registerBeanPostProcessors() → 把实例阶段的增强器排好序。
- finishBeanFactoryInitialization() → 真正实例化非懒加载单例。
- finishRefresh() → 发布 ContextRefreshedEvent 等收尾动作。
想象你在租一间毛坯办公室:prepareRefresh() 像是验收水电、检查网络是否通。obtainFreshBeanFactory() 把空房打扫干净准备装修。prepareBeanFactory() 先把公共设施(饮水机、打印机)搬进来。postProcessBeanFactory() 如果你有特殊需求(比如隔出会议室),可以在这一步动手。接着两拨装修队依次进场:第一拨改图纸(BeanFactoryPostProcessor),第二拨负责软装(BeanPostProcessor)。finishBeanFactoryInitialization() 就是把桌椅板凳全部装配好。最后 finishRefresh() 剪彩开业,通知大家可以正常办公了。

三、BeanDefinition 从哪来?
3.1 XML 解析
ini
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("beans.xml");
内部委托 BeanDefinitionParserDelegate
,把 <bean>
、<context:component-scan>
等标签转成 BeanDefinition
。
3.2 注解扫描
AnnotationConfigApplicationContext
启动后会触发 ConfigurationClassPostProcessor
,扫描 @Configuration/@Component
,同样得到 BeanDefinition
。
结论:资源形式千差万别,落地结果都在 BeanDefinitionRegistry
的那张 Map 里。

四、元数据阶段的扩展:BeanFactoryPostProcessor
调用栈:refresh()
→ invokeBeanFactoryPostProcessors()
→ PostProcessorRegistrationDelegate
。
执行顺序按接口排序:PriorityOrdered → Ordered → 普通
。
典型场景:
- MyBatis 的
MapperScannerConfigurer
- Spring Boot 的
ConfigurationClassPostProcessor
(解析@EnableAutoConfiguration
)
五、实例阶段的扩展:BeanPostProcessor
注册发生在 registerBeanPostProcessors()
,之后每个 Bean 创建都会走一遍列表里的 Processor。
常见实现:
AutowiredAnnotationBeanPostProcessor
:处理@Autowired
、@Value
AopProxyCreator
:生成 AOP 代理ApplicationContextAwareProcessor
:注入各种xxxAware
六、doCreateBean 内幕
- A:某些 InstantiationAwareBeanPostProcessor(如 AOP)可在真正 new 对象前直接返回代理,跳过后续流程。
- B createBeanInstance:挑构造器、反射或 CGLIB 生成实例。
- C populateBean:完成依赖注入、@Autowired、字段填充。
- D initializeBean:执行各种回调:Aware、@PostConstruct、BeanPostProcessor 的 before/after。
- E registerDisposableBeanIfNecessary:如是单例且实现了 DisposableBean,注册销毁回调。
我们用做菜来举例,A 厨子有时会发现食材已经是现成半成品(代理对象),就不用再切洗。B 选刀具 + 切配 = 创建实例。C 加盐、味精、下配料 = 属性注入。D 开火翻炒到收汁 = 初始化阶段。E 把锅盖好、记住关火步骤 = 注册销毁回调。最终一道成品菜端上桌(返回 Bean)。

源码(精简):
scss
protected Object doCreateBean(String name, RootBeanDefinition mbd, Object[] args) {
BeanWrapper bw = createBeanInstance(name, mbd, args); // 构造
populateBean(name, mbd, bw); // 属性注入
return initializeBean(name, bw.getWrappedInstance(), mbd); // 回调 + BPP
}
七、生命周期回调速查
- 构造函数 / 工厂方法
- 依赖注入(
@Autowired
) BeanNameAware / BeanFactoryAware / EnvironmentAware ...
BeanPostProcessor#postProcessBeforeInitialization
InitializingBean#afterPropertiesSet
或@PostConstruct
BeanPostProcessor#postProcessAfterInitialization
- 容器关闭:
DisposableBean#destroy
、@PreDestroy
、DestructionAwareBeanPostProcessor
八、三级缓存与循环依赖
- singletonFactories 保存的是 ObjectFactory,调用它可获得「只执行构造、不跑初始化」的早期对象。
- earlySingletonObjects 放已经拿出来用过的早期对象。
- singletonObjects 只有完成全部生命周期的 Bean 才能晋级。
- 当 Bean A 构造完,但初始化前依赖了 Bean B,容器会把 A 的 ObjectFactory 暂存到三级缓存,让 B 可以先拿到「半成品 A」,避免死循环。
把三级缓存想成奶茶店的 3 个货架:三级货架 是奶茶原液,你自己加冰加料才喝得下。二级货架 是加好冰却没封口的杯子,员工可以先尝一口。一级货架 才是贴好封膜、可以递给顾客的成品。有顾客点了「连锁奶茶 + 甜品组合」导致两边互相依赖时,店员就会把「原液」先放到三级货架,另一边可以先用,等两杯都弄好再一起封口。

九、依赖解析小细节
调用链:resolveDependency()
→ doResolveDependency()
关键点:
- 同类型候选 Bean 名先拿出来
- 如果参数带
@Qualifier
,精确匹配 - 对集合 / 数组参数按顺序注入
Optional<T>
、ObjectProvider<T>
也是这里处理
十、Spring Boot 与自动装配
Boot 在 SpringApplication#refreshContext()
里依旧调用 refresh()
,只是多注册了若干 BeanFactoryPostProcessor:
ConfigurationClassPostProcessor
:识别@EnableAutoConfiguration
AutoConfigurationImportSelector
:从spring.factories
里挑符合条件的配置类ConditionEvaluationReport
:筛掉不满足@Conditional
的 BeanDefinition
一句话:Boot 只是「写了很多 PostProcessor」,底层流程没变。
十一、自定义扩展示例
11.1 BeanFactoryPostProcessor 给 Mapper 加表名前缀
typescript
@Component
public class TablePrefixProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {
for (String name : bf.getBeanDefinitionNames()) {
if (name.endsWith("Mapper")) {
BeanDefinition bd = bf.getBeanDefinition(name);
bd.getConstructorArgumentValues()
.addIndexedArgumentValue(0, "demo_" + name);
}
}
}
}
11.2 BeanPostProcessor 统计初始化耗时
typescript
@Component
public class TimerPostProcessor implements BeanPostProcessor {
private final Map<String, Long> ts = new ConcurrentHashMap<>();
public Object postProcessBeforeInitialization(Object bean, String name) {
ts.put(name, System.nanoTime());
return bean;
}
public Object postProcessAfterInitialization(Object bean, String name) {
long cost = System.nanoTime() - ts.remove(name);
System.out.printf("%s 初始化耗时 %d μs%n", name, cost / 1000);
return bean;
}
}
十二、知识卡片
场景 | 关键接口 / 类 |
---|---|
元数据扩展 | BeanFactoryPostProcessor , BeanDefinitionRegistryPostProcessor |
实例扩展 | BeanPostProcessor , InstantiationAwareBeanPostProcessor |
生命周期 | InitializingBean , DisposableBean , *Aware , @PostConstruct |
缓存 | singletonObjects , earlySingletonObjects , singletonFactories |
Boot 自动装配 | ConfigurationClassPostProcessor , AutoConfigurationImportSelector |
当你把 AbstractAutowireCapableBeanFactory#doCreateBean()
的调用栈捋顺,再配合两类 PostProcessor 的时机点,Spring 的「黑魔法」基本就拆完了。此后不管是写自定义 Starter,还是排查循环依赖、Bean 覆盖等疑难杂症,都能快速定位到源码里对应的阶段。
愿这份笔记能帮你把 IoC 容器的运行机理牢牢刻进肌肉记忆。