IOC - refresh
Spring IOC 容器启动:refresh() 十二步
refresh() 解决的问题:把一个刚 new 出来的空壳 ApplicationContext 变成完全可用的 IOC 容器。
XML、注解、Spring Boot 的启动入口殊途同归,最终都汇到这个模板方法,十二步顺序写死,子类和扩展点只能往固定的槽位里塞内容,改不了流程本身。
本地快照是 v5.3.39;6.1 起入口锁从 synchronized 换成了 startupShutdownLock(ReentrantLock,避免 synchronized 钉住虚拟线程),但十二步骨架十多年没变过。
代码块收起展开
// 基于本地 Spring 仓 (v5.3.39), org.springframework.context.support.AbstractApplicationContext#refresh
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) { // 和 close()/doClose() 共用同一把监视器锁: 启动与销毁绝不并发
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); // 启动耗时埋点, 默认实现是空操作
// Prepare this context for refreshing.
prepareRefresh(); // 1. 置 active 标志、校验必需属性、准备早期事件暂存集合
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 2. 拿到 DefaultListableBeanFactory; 注解驱动下 BeanDefinition 大多还没进来, 留给第 5 步扫描
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); // 3. 给工厂做标配: Aware 回调、可解析依赖、environment 等内置单例
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // 4. 子类钩子: Web 容器在此注册 request/session 作用域
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // 5. 执行 BeanFactoryPostProcessor: 配置类解析、包扫描都在这, 把"定义"补齐
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); // 6. 只注册不调用: AOP 代理创建器等在此排好序就位, 等第 11 步创建 bean 时才回调
beanPostProcess.end();
// Initialize message source for this context.
initMessageSource(); // 7. 国际化; 没配就注册一个空实现兜底
// Initialize event multicaster for this context.
initApplicationEventMulticaster(); // 8. 事件广播器, publishEvent 的底层设施
// Initialize other special beans in specific context subclasses.
onRefresh(); // 9. 子类钩子: Boot 内嵌 Tomcat 的 createWebServer 就在这里
// Check for listener beans and register them.
registerListeners(); // 10. 挂监听器 + 补发早期事件
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // 11. 实例化全部非懒加载单例: 依赖注入、AOP 织入、循环依赖处理都发生在这一步内部
// Last step: publish corresponding event.
finishRefresh(); // 12. 启动 Lifecycle 组件, 发布 ContextRefreshedEvent
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans(); // 启动失败销毁已建单例: 半成品容器不能泄漏连接池、线程这类资源
// Reset 'active' flag.
cancelRefresh(ex); // active 置回 false, 之后再 getBean 直接抛 IllegalStateException
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches(); // 成败都清反射/注解元数据缓存: 这些缓存只为启动期装配服务, 单例建完就是死重
contextRefresh.end();
}
}
}前三步是准备阶段,重点看两处:earlyApplicationEvents 的暂存设计,和 prepareBeanFactory 里 ignore 与 register 成对出现的依赖规则。
代码块收起展开
// 基于本地 Spring 仓 (v5.3.39), AbstractApplicationContext 准备阶段三个方法
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false); // closed/active 是两个 AtomicBoolean: close() 过的容器理论上还能再 refresh 复活
this.active.set(true);
// ... 日志输出省略
// Initialize any placeholder property sources in the context environment.
initPropertySources(); // 子类钩子: Web 环境把 servletContextInitParams 这类占位 PropertySource 换成真实例
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties(); // 必需属性缺失在启动第一步就快速失败, 不拖到运行时
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners); // 支持重复 refresh: 把监听器列表还原到首次 refresh 前的快照
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>(); // 广播器第 8 步才建, 此前发的事件先攒在这, 第 10 步统一补发
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory(); // 子类实现: XML 系容器销毁旧工厂重建并 loadBeanDefinitions; GenericApplicationContext 只做一次性校验, 工厂构造时就建好了
return getBeanFactory();
}
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
if (!shouldIgnoreSpel) {
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // @Value("#{...}") 的 SpEL 解析能力从这来
}
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 各种 Aware 接口的注入靠这个 BeanPostProcessor 在初始化前回调
beanFactory.ignoreDependencyInterface(EnvironmentAware.class); // 成对设计: Aware 的 setter 不参与按类型自动装配, 注入职责已归上面的 Processor, 防二次注入
// ... 其余 6 个 ignoreDependencyInterface(XxxAware.class) 同理省略
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); // 反向操作: 这四个类型没有 BeanDefinition, 但 @Autowired 必须能注入
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this); // 注入 ApplicationContext 拿到的就是容器自身 this
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // 实现 ApplicationListener 的 bean 初始化完自动挂上广播器
// ... LoadTimeWeaver 检测省略
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); // 以手工单例注册, 不走 bean 创建流程
}
// ... systemProperties / systemEnvironment / applicationStartup 三个同理省略
}真正要记死的是 5、6、11 三步。第 5 步把”定义”补齐,第 6 步把”实例加工器”排好队,第 11 步才统一实例化。
代码块收起展开
// 基于本地 Spring 仓 (v5.3.39), AbstractApplicationContext 第 5/6/10/11/12 步实现
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // 真正干活的委托类: 先 BeanDefinitionRegistryPostProcessor 后普通 BFPP, 各自按 PriorityOrdered > Ordered > 无序执行
// ... LoadTimeWeaver 兜底检测省略
}
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); // 委托类里会 getBean 把所有 BPP 提前实例化并排序注册, 但一个都不回调
}
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); // 只按类型查名字不触发实例化: 此刻 getBean 会让监听器漏掉 BPP 加工
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); // 登记的是 beanName, 实例化推迟到第 11 步
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null; // 置 null 同时是个开关: 此后 publishEvent 直接走广播器, 不再进暂存集合
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent); // 把 prepareRefresh 起攒下的早期事件补发出去
}
}
}
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no BeanFactoryPostProcessor
// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); // ${} 占位符解析的兜底实现
}
// ... LoadTimeWeaverAware 与临时 ClassLoader 处理省略
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration(); // 冻结定义: 从此可以放心缓存 merged BeanDefinition, 元数据不许再改
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons(); // 十二步里最重的一行: 遍历全部 beanDefinitionNames 逐个 getBean
}
@SuppressWarnings("deprecation")
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh(); // 启动所有 autoStartup 的 SmartLifecycle: 消息监听容器这类"活"组件从这里跑起来
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this)); // 容器就绪的官方信号, 启动后初始化逻辑监听它最稳
// Participate in LiveBeansView MBean, if active.
if (!NativeDetector.inNativeImage()) {
LiveBeansView.registerApplicationContext(this); // 5.3 已废弃, 6.0 连同这段代码一起删除
}
}原理串讲
拿 new AnnotationConfigApplicationContext(AppConfig.class) 走一遍。
构造器先 register(AppConfig),此刻 DefaultListableBeanFactory 里只有 AppConfig 自己和几个内置处理器的 BeanDefinition(最关键的是 ConfigurationClassPostProcessor),然后进 refresh()。
prepareRefresh() 里最值得看的是 earlyApplicationEvents = new LinkedHashSet<>() 这行:事件广播器要到第 8 步才创建,但 publishEvent 从容器一出生就可能被调用,为什么不直接报错或丢弃?Spring 选择先攒后补,publishEvent 内部判断暂存集合非 null 就只入集合,registerListeners() 末尾把集合置 null 并把攒下的事件逐个 multicastEvent 补发。
用一个字段同时当缓冲区和开关,事件一条不丢,也不需要额外的状态机。第 2 步 obtainFreshBeanFactory() 在注解容器里几乎是空操作(GenericApplicationContext.refreshBeanFactory 只 CAS 校验不许二次 refresh),XML 系的 AbstractRefreshableApplicationContext 则在这里销毁旧工厂、重建、loadBeanDefinitions 解析 XML,这也是”XML 容器定义在第 2 步齐、注解容器定义在第 5 步齐”的分岔点。
代码块收起展开
第 5 步 `invokeBeanFactoryPostProcessors` 委托给 `PostProcessorRegistrationDelegate`:先执行所有 `BeanDefinitionRegistryPostProcessor`,其中 `ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry` 解析 `@Configuration`、`@ComponentScan`、`@Bean`、`@Import`,递归扫描把成百上千个 BeanDefinition 注册进工厂;再执行普通 `BeanFactoryPostProcessor`,比如同一个类的 `postProcessBeanFactory` 会给 `@Configuration` 类做 CGLIB 增强,保证配置类里 `@Bean` 方法互调时拿到的是容器单例而非新对象。
为什么把"改定义"和"实例化"切成两个阶段?因为 BFPP 面对的是元数据,此时改 scope、改属性值、加减定义都还来得及;一旦开始实例化,定义就被 merge 并缓存,再改也不生效。阶段切开后每个扩展点的语义边界非常清楚:BFPP 改”图纸”,BPP 改”成品”。
第 6 步 registerBeanPostProcessors 把所有 BPP 提前 getBean 出来、按序 addBeanPostProcessor,但一个也不回调。
为什么只注册不调用?因为 BPP 的回调点位长在每个 bean 的创建流程内部(初始化前后各一次),它必须赶在任何业务 bean 实例化之前全部就位,否则先创建的 bean 会漏掉 AOP 织入这类加工;谁要是被过早实例化,日志里 BeanPostProcessorChecker 就会告警 “is not eligible for getting processed by all BeanPostProcessors”。
这也是第 10 步 registerListeners 只登记 beanName 不实例化监听器的原因:监听器也是 bean,也要完整走一遍加工线。
第 11 步 finishBeanFactoryInitialization 先 freezeConfiguration() 冻结定义,然后 preInstantiateSingletons() 遍历 beanDefinitionNames 逐个 getBean → doGetBean → createBean → doCreateBean:实例化、populateBean 属性注入、initializeBean 初始化,AOP 代理在 postProcessAfterInitialization 里把原对象换掉,循环依赖靠三级缓存提前暴露半成品(细节见 循环依赖-三级缓存 与 AOP-动态代理)。
全部单例建完后还会回调 SmartInitializingSingleton.afterSingletonsInstantiated,@EventListener 注解方法就是这时被解析成监听器挂上广播器的。
第 12 步 finishRefresh 里 getLifecycleProcessor().onRefresh() 启动所有 autoStartup 的 SmartLifecycle,最后 publishEvent(new ContextRefreshedEvent(this)) 广播容器就绪。
失败路径同样有设计:catch 里 destroyBeans() 逐个执行已建单例的销毁回调,防止半成品容器泄漏连接池和线程;cancelRefresh 把 active 置 false,此后 getBean 直接抛 IllegalStateException,杜绝一个启动失败的容器被继续使用。
finally 里 resetCommonCaches() 成败都执行,把反射、注解、ResolvableType 的元数据缓存清空,这批缓存只在装配期有用,单例建完留着就是白占内存。
设计取舍
- 模板方法把顺序焊死,扩展全走钩子(
postProcessBeanFactory/onRefresh)和处理器(BFPP/BPP):子类只能改内容改不了流程,这是 refresh 骨架十几年不腐的原因。 - BFPP 改定义、BPP 改实例,别混用:在 BFPP 里
getBean是经典误用,会把 bean 提前实例化、绕开尚未注册的后置处理器。 - 事件系统对启动时序免疫:第 8 步前发的事件进
earlyApplicationEvents暂存补发,监听器 bean 第 11 步才实例化但第 10 步已按名登记,两头都不丢。 - 单例默认非懒加载是刻意的:启动慢一点,换来配置错误在启动期全部暴露,运行时
getBean只剩查缓存。 - 5.3.x 用 synchronized 锁整个 refresh;6.1 起换成
startupShutdownLock(ReentrantLock),主因是虚拟线程时代 synchronized 长临界区会钉住载体线程。