简单介绍
ConfigurableApplicationContext 是 Spring 的 SPI 接口 (org.springframework.context.ConfigurableApplicationContext),是可配置、可刷新、可关闭的 ApplicationContext ,SpringBoot SpringApplication.run() 返回值就是这个类型。
定位:ApplicationContext 的可修改版本,负责容器生命周期管控,面向框架启动 / 销毁代码,业务代码尽量不要直接调用它的 refresh/close。
架构设计
plaintext
BeanFactory(基础Bean获取)
↑
ApplicationContext(增强:事件、国际化、资源、层级容器)
↑
ConfigurableApplicationContext(SPI:新增【配置能力 + 完整生命周期】)
├─ ConfigurableWebApplicationContext(web环境子接口)
└─ 实现:AbstractApplicationContext(核心实现,几乎所有上下文都继承它)
接口隔离原则 ISP
ApplicationContext:面向业务应用层 ,只暴露查询、获取 Bean、发布事件等只读能力,隐藏容器危险操作;ConfigurableApplicationContext:面向Spring 框架、启动器、中间件、测试代码 的 SPI,暴露修改配置、生命周期、内部工厂操作。
设计目的:业务代码拿
ApplicationContext看不到refresh()/close()这类高危方法,避免业务随意篡改容器状态引发不可预期问题。只有强转成ConfigurableApplicationContext才能调用生命周期方法。
完整容器生命周期模型
定义标准状态流转:
未初始化 → refresh()刷新启动 → isActive=true运行态 → close()关闭 → isActive=false销毁
new容器对象 → refresh()【核心启动】 → 容器运行 → registerShutdownHook注册钩子 → close()销毁
refresh 具备原子性:刷新失败必须销毁已经实例化的单例 Bean,不能留下半初始化容器。
扩展点预埋设计
提供addBeanFactoryPostProcessor、addApplicationListener,允许外部在容器 refresh 阶段插入自定义逻辑,支撑@Configuration解析、自动配置、事件监听。
父子容器支持
setParent() 支持层级容器,经典场景 SpringMVC:
- Root 上下文 (父):Service、DAO;
- Servlet 子上下文:Controller;
规则:父容器 Bean 对子容器可见,子容器 Bean 对父容器不可见;关闭子容器不会关闭父容器。
门面模式
ApplicationContext是门面,真正的 Bean 仓库是内部ConfigurableListableBeanFactory。getBeanFactory()拿到底层真实 Bean 工厂,但这是后门,有严格使用时机限制。
源码解析
java
package org.springframework.context;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import java.io.Closeable;
/**
* SPI接口,ApplicationContext的可配置版本
* 代表一个具备完整生命周期、可修改配置、可刷新关闭的Spring IoC容器
* 注意:本接口方法主要供Spring框架内部调用,业务代码谨慎使用;
* SpringApplication.run()返回的上下文实例就是该接口实现。
*/
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
/**
* 配置路径分隔符常量
* 在单个字符串配置多个配置文件路径时,可用这些符号分割:逗号、分号、空格、制表符、换行
* 例:classpath:bean1.xml,classpath:bean2.xml
*/
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
/**
* 容器中ConversionService转换器Bean的beanName
* ConversionService用于Spring类型转换,比如String转Date、字符串转自定义对象
* 用户可以自定义id=conversionService的Bean覆盖默认转换规则
*/
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
/**
* 类加载时织入LoadTimeWeaver的beanName
* 用于LTW(加载时AOP织入),在类被ClassLoader加载字节码的时候做增强
*/
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
/**
* Environment环境对象在容器中的beanName
* Environment存放profile、配置属性源(application.yml、系统属性、环境变量)
*/
String ENVIRONMENT_BEAN_NAME = "environment";
/**
* systemProperties bean名称,封装JVM系统属性 System.getProperties()
*/
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
/**
* systemEnvironment bean名称,封装操作系统环境变量 System.getenv()
*/
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
/**
* 设置当前上下文唯一ID
* 每个ApplicationContext实例有一个id标识,日志输出、监控会打印该id;
* SpringBoot会自动生成,也可以手动覆盖设置。
* @param id 上下文标识字符串
*/
void setId(String id);
/**
* 设置父容器,构建父子层级IoC容器
* 注意:只允许在容器构造/refresh之前设置,refresh运行后不建议修改父容器;
* 典型场景SpringMVC:root上下文作为父,servlet上下文作为子容器。
* 父容器Bean对子容器可见;子Bean对父不可见。close()子容器不会关闭父容器。
* @param parent 父上下文
*/
void setParent(ApplicationContext parent);
/**
* 获取可修改的Environment对象
* 继承自ApplicationContext,返回ConfigurableEnvironment,
* 可以新增配置源、激活/关闭profile,修改环境属性。
* @return 可配置环境对象
*/
@Override
ConfigurableEnvironment getEnvironment();
/**
* 替换容器的Environment环境对象
* ⚠️必须refresh()执行之前调用;refresh之后再修改环境会引发不可预知bug。
* @param environment 新的环境实例
*/
void setEnvironment(ConfigurableEnvironment environment);
/**
* 注册BeanFactoryPostProcessor后置处理器
* 执行时机:refresh流程中,BeanDefinition全部加载完毕,Bean实例化之前执行;
* 可以修改BeanDefinition定义信息。例如ConfigurationClassPostProcessor解析@Configuration。
* ⚠️重要:必须refresh()调用之前添加;refresh之后再添加不会被执行。
* @param beanFactoryPostProcessor Bean工厂后置处理器
*/
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor);
/**
* 注册应用事件监听器ApplicationListener
* 1、容器未激活(refresh未执行):注册后refresh阶段就可以收到容器生命周期事件;
* 2、容器已经激活运行:会直接交给当前事件广播器,立刻生效监听后续事件;
* 可监听事件:ContextRefreshedEvent容器刷新完成、ContextClosedEvent容器关闭事件。
* @param listener 事件监听器
*/
void addApplicationListener(ApplicationListener<?> listener);
/**
* ✨【Spring IoC容器最核心启动入口】刷新容器
* 加载/刷新配置元数据,可以是xml、注解配置、properties配置;
* 完整流程:准备环境→创建BeanFactory→加载BeanDefinition→执行BFPP→注册BPP→实例化非懒加载单例Bean→发布容器就绪事件。
* 原子性保证:如果refresh中途抛出异常,会销毁已经创建的单例Bean;
* 要么全部Bean初始化成功,要么全部销毁,不会残留半初始化容器。
* 限制:大部分实现不支持重复多次refresh(),重复调用抛出IllegalStateException。
* @throws BeansException Bean解析、实例化失败抛出
* @throws IllegalStateException 容器状态非法,例如已经刷新过、已经关闭
*/
void refresh() throws BeansException, IllegalStateException;
/**
* 向JVM注册关闭钩子ShutdownHook
* JVM正常退出时(System.exit,正常kill信号)自动执行本容器close();
* kill‑9强制终止进程不会执行钩子。
* 多次调用该方法只会注册最多一个钩子,不会重复注册。
* SpringBoot应用默认会调用该方法,实现优雅销毁Bean执行@PreDestroy。
* @see java.lang.Runtime#addShutdownHook
* @see #close()
*/
void registerShutdownHook();
/**
* 关闭当前上下文,释放全部资源,销毁所有缓存的单例Bean;
* 执行Bean销毁回调@PreDestroy、DisposableBean;发布ContextClosedEvent事件。
* ⚠️不会调用父容器的close,父子容器生命周期互相独立。
* 幂等方法:多次调用close()不会报错,已经关闭的上下文再次调用直接忽略。
* 继承Closeable,支持try‑with‑resources语法自动关闭容器。
*/
@Override
void close();
/**
* 判断容器是否处于激活运行状态
* 激活条件:至少执行过一次refresh(),并且尚未调用close()关闭;
* 很多框架扩展代码调用getBean前会先判断isActive做状态守卫。
* @return true=运行中;false=未初始化或者已经关闭
*/
boolean isActive();
/**
* 获取底层内部Bean工厂 ConfigurableListableBeanFactory,真实Bean仓库。
* 底层实现类一般是 DefaultListableBeanFactory。
*
* ⚠️官方重要警告:
* 不要拿返回的BeanFactory做后置处理!refresh完成后单例已经实例化完成,此时修改工厂来不及。
* 如果需要修改Bean定义,要用 BeanFactoryPostProcessor,在Bean实例化之前介入。
*
* 调用时机:只能在refresh()之后、close()之前,也就是isActive()=true期间。
* refresh还没调用,或者已经close,调用直接抛出IllegalStateException。
*
* @return 底层Bean工厂
* @throws IllegalStateException 容器没有可用内部Bean工厂(未refresh或者已关闭)
*/
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
关键实现类
接口本身只是契约,逻辑全部在实现:
AbstractApplicationContext:抽象模板类,实现 refresh () 完整 12 步模板方法,绝大多数上下文继承它;AnnotationConfigApplicationContext:注解独立非 web 容器;AnnotationConfigServletWebServerApplicationContext:SpringBoot Web 环境默认上下文;GenericApplicationContext:通用容器,适合动态注册 BeanDefinition,测试、中间件大量使用。
重点方法深度总结
refresh()
容器启动心脏,12 步标准 IoC 初始化 。
不支持重复刷新;失败要销毁 Bean;业务禁止手动调用。
getBeanFactory()
获取底层 Bean 仓库后门。
refresh 前 /close 后调用抛异常;不要 refresh 完成后修改 BeanDefinition。
addBeanFactoryPostProcessor
添加 Bean 工厂后置处理器 。
refresh 之后添加不会执行。
addApplicationListener
添加事件监听器 。
refresh 前注册可接收刷新事件;refresh 后注册只能监听后续新事件。
registerShutdownHook()
JVM 关闭钩子。
kill‑9 不会触发销毁;只针对正常退出。
close()
销毁容器 。
幂等;不会关闭父容器。
setParent()
设置父子容器。
refresh 后禁止修改父容器。