版权声明
- 本文原创作者:谷哥的小弟
- 作者博客地址:http://blog.csdn.net/lfdfhl

一、引言
在 Spring Framework 的核心容器体系中,应用上下文(Application Context) 是 IoC 容器的高级形态,它不仅提供依赖注入能力,还集成了事件发布、国际化、资源加载、AOP 等企业级特性。而 ConfigurableApplicationContext 则是这一上下文模型中的可配置扩展接口,为容器的生命周期管理、环境定制、刷新控制等关键操作提供了标准化的编程入口。
作为 ApplicationContext 的直接子接口,ConfigurableApplicationContext 并不关注业务 Bean 的使用,而是聚焦于容器自身的构建、配置与运行时控制 。它是 Spring 容器启动流程(如 refresh())、关闭流程(如 close())、以及运行时动态干预(如设置环境、注册监听器)的核心契约。
本文将对 ConfigurableApplicationContext 进行全面、深入、严谨的技术剖析。我们将从其接口设计、继承体系、核心方法语义、典型实现类(如 AbstractApplicationContext)、与 Spring Boot 的集成方式,到其在容器生命周期中的关键作用逐一展开,并辅以关键源码解读,力求揭示 Spring 容器可配置性与扩展性的底层机制。
二、接口定义与设计目标
2.1 接口源码
java
package org.springframework.context;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.lang.Nullable;
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
/**
* 设置此应用上下文的唯一 ID。
*/
void setId(String id);
/**
* 设置此上下文的父上下文。
*/
void setParent(@Nullable ApplicationContext parent);
/**
* 设置此上下文使用的环境。
* 必须在 refresh() 之前调用。
*/
void setEnvironment(ConfigurableEnvironment environment);
/**
* 返回此上下文的可配置环境。
*/
@Override
ConfigurableEnvironment getEnvironment();
/**
* 添加一个 ApplicationListener,用于监听上下文事件。
* 可在 refresh() 之前或之后调用。
*/
void addApplicationListener(ApplicationListener<?> listener);
/**
* 添加一个 BeanFactoryPostProcessor,在 Bean 定义加载后、Bean 实例化前执行。
*/
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
/**
* 加载或刷新持久化的配置(如 XML、注解、Java 配置),
* 使上下文进入可用状态。
* 此方法是线程安全的,且应仅被调用一次。
*/
void refresh() throws BeansException, IllegalStateException;
/**
* 注册一个关闭钩子(Shutdown Hook),在 JVM 退出时自动关闭上下文。
*/
void registerShutdownHook();
/**
* 关闭此应用上下文,释放所有资源,销毁所有单例 Bean。
* 实现了 java.io.Closeable 接口。
*/
@Override
void close();
/**
* 返回底层的可配置 BeanFactory。
* 允许对容器内部进行低级操作(谨慎使用)。
*/
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
2.2 设计目标
| 目标 | 说明 |
|---|---|
| 容器可配置性 | 允许在启动前设置 ID、父上下文、环境、后处理器等 |
| 生命周期控制 | 提供 refresh() 和 close() 标准化容器启停 |
| 运行时扩展 | 支持动态添加监听器和后处理器 |
| 与底层解耦 | 通过 getBeanFactory() 暴露底层,但鼓励使用高层 API |
| JVM 集成 | 通过 registerShutdownHook() 实现优雅关闭 |
核心思想 :
"容器即对象,可构建、可配置、可销毁" ------ 将应用上下文视为一个具有完整生命周期的可编程实体。
三、继承体系与典型实现
3.1 接口继承关系
org.springframework.context.ApplicationContext
└── org.springframework.context.ConfigurableApplicationContext
└── org.springframework.web.context.ConfigurableWebApplicationContext (Web 扩展)
└── org.springframework.web.context.support.XmlWebApplicationContext
└── org.springframework.web.context.support.AnnotationConfigWebApplicationContext
org.springframework.context.support.AbstractApplicationContext (抽象基类)
├── ClassPathXmlApplicationContext
├── FileSystemXmlApplicationContext
├── AnnotationConfigApplicationContext
└── GenericApplicationContext
AbstractApplicationContext:实现了ConfigurableApplicationContext的绝大部分通用逻辑;GenericApplicationContext:更灵活的通用实现,支持任意BeanDefinitionRegistry;- Web 扩展 :
ConfigurableWebApplicationContext增加了 Servlet 上下文、命名空间等 Web 特性。
四、核心方法深度解析
4.1 refresh():容器初始化的核心
这是 Spring 容器启动流程的总入口,其执行过程定义了标准的容器初始化阶段。
4.1.1 refresh() 源码(AbstractApplicationContext)
java
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备刷新:记录启动时间、激活标志、验证环境等
prepareRefresh();
// 2. 获取(或创建)内部 BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 配置 BeanFactory 的标准特性(如类加载器、表达式解析器)
prepareBeanFactory(beanFactory);
try {
// 4. 允许子类进一步定制 BeanFactory(模板方法)
postProcessBeanFactory(beanFactory);
// 5. 调用所有已注册的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册所有 BeanPostProcessor(注意:此时还未实例化 Bean)
registerBeanPostProcessors(beanFactory);
// 7. 初始化消息源(国际化)
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 允许子类执行特殊刷新逻辑(如 Web 容器初始化 ServletContext)
onRefresh();
// 10. 注册 ApplicationListener(包括静态定义的和通过 getApplicationListeners() 获取的)
registerListeners();
// 11. 完成 BeanFactory 初始化:实例化所有非懒加载的单例
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新:发布 ContextRefreshedEvent
finishRefresh();
} catch (BeansException ex) {
// 销毁已创建的单例,避免内存泄漏
destroyBeans();
cancelRefresh(ex);
throw ex;
} finally {
// 重置公共缓存(如 ReflectionUtils、AnnotationUtils)
resetCommonCaches();
}
}
}
关键洞察:
- 12 步标准化流程:确保所有 Spring 容器行为一致;
- 模板方法模式 :
postProcessBeanFactory()和onRefresh()允许子类扩展;- 异常安全:失败时自动清理已创建的 Bean;
- 事件驱动 :最后发布
ContextRefreshedEvent,通知监听器容器就绪。
4.2 close():容器销毁流程
java
@Override
public void close() {
synchronized (this.startupShutdownMonitor) {
doClose(); // 执行关闭逻辑
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
} catch (IllegalStateException ex) {
// ignore
}
}
}
}
protected void doClose() {
if (this.active.get() && this.closed.compareAndSet(false, true)) {
// 发布 ContextClosedEvent
publishEvent(new ContextClosedEvent(this));
// 销毁所有 Lifecycle Bean
if (this.lifecycleProcessor != null) {
this.lifecycleProcessor.onClose();
}
// 销毁所有单例 Bean
destroyBeans();
// 关闭 BeanFactory
closeBeanFactory();
// 重置本地状态
onClose();
// 标记为 inactive
this.active.set(false);
}
}
- 优雅关闭:先发事件,再销毁 Bean,最后清理资源;
- 幂等性 :通过
closed原子变量确保多次调用安全; - Lifecycle 支持 :调用
LifecycleProcessor.onClose(),允许组件自定义关闭逻辑。
4.3 getBeanFactory():暴露底层容器
java
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
if (!this.active.get()) {
throw new IllegalStateException("Context has not been refreshed yet");
}
return this.beanFactory;
}
- 安全检查 :仅在
refresh()成功后允许访问; - 返回类型 :
ConfigurableListableBeanFactory提供完整的 Bean 操作能力(如getBeansOfType,containsBeanDefinition); - 谨慎使用:破坏了 ApplicationContext 的封装性,应优先使用高层 API。
4.4 setEnvironment() 与 getEnvironment()
java
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
this.environment = environment;
}
@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment(); // 默认创建 StandardEnvironment
}
return this.environment;
}
- 时机敏感 :必须在
refresh()前调用,否则无效; - 典型用途 :Spring Boot 在启动时替换为
StandardServletEnvironment。
4.5 addBeanFactoryPostProcessor() 与 addApplicationListener()
java
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
@Override
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
this.beanFactoryPostProcessors.add(postProcessor);
}
- 动态注册 :允许在
refresh()前添加自定义后处理器; - 执行时机 :在
invokeBeanFactoryPostProcessors()阶段统一调用; - 应用场景 :Spring Boot 的
ConfigurationPropertiesBindingPostProcessor通过此方式注入。
五、与 Spring Boot 的集成
Spring Boot 的 SpringApplication 高度依赖 ConfigurableApplicationContext:
java
// SpringApplication.java
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
protected void prepareContext(ConfigurableApplicationContext context, ...) {
context.setEnvironment(environment);
applyInitializers(context); // 调用 ApplicationContextInitializer
listeners.contextPrepared(context);
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
public ConfigurableApplicationContext run(String... args) {
context = createApplicationContext();
prepareContext(context, ...);
refreshContext(context); // 调用 context.refresh()
afterRefresh(context, ...);
return context;
}
ApplicationContextInitializer:在refresh()前对ConfigurableApplicationContext进行定制;- 生命周期钩子 :
SpringApplicationRunListener在关键节点(如contextPrepared)介入。
六、典型实现类分析:GenericApplicationContext
GenericApplicationContext 是最灵活的实现,常用于测试或程序化构建容器:
java
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("myService", MyService.class);
context.registerBean("dataSource", DataSource.class, () -> createDataSource());
context.refresh(); // 触发初始化
MyService service = context.getBean(MyService.class);
context.close();
- 内部持有
DefaultListableBeanFactory; - 支持任意
BeanDefinition注册; - 适用于无 XML/注解的纯 Java 配置场景。
七、使用场景与最佳实践
7.1 动态构建容器(测试场景)
java
@Test
void testWithCustomContext() {
try (GenericApplicationContext context = new GenericApplicationContext()) {
context.registerBean(FooService.class);
context.refresh();
assertThat(context.getBean(FooService.class)).isNotNull();
} // 自动 close()
}
7.2 自定义初始化逻辑
java
public class MyApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(myPostProcessor());
applicationContext.getEnvironment().getSystemProperties().put("custom.prop", "value");
}
}
7.3 最佳实践
- 避免直接调用
refresh()多次:设计上仅支持一次; - 始终调用
close()或使用 try-with-resources:防止资源泄漏; - 优先使用
ApplicationContextInitializer而非硬编码:提升可配置性; - 不要在
refresh()后修改环境:此时环境已冻结。
八、总结
ConfigurableApplicationContext 是 Spring 容器可配置性与生命周期管理的核心接口,其设计体现了以下关键原则:
- 标准化生命周期 :通过
refresh()/close()定义清晰的启停契约; - 高度可扩展:支持动态添加后处理器、监听器、自定义环境;
- 分层抽象 :高层
ApplicationContext与底层BeanFactory解耦; - 事件驱动 :通过
ApplicationEvent实现松耦合的容器状态通知; - 安全与幂等:同步控制、状态检查、异常清理保障稳定性。
| 维度 | 关键结论 |
|---|---|
refresh() |
12 步标准化初始化流程,模板方法支持扩展 |
close() |
优雅关闭,发布事件,销毁 Bean,幂等安全 |
| 环境设置 | 必须在 refresh() 前完成 |
| 后处理器注册 | 动态添加,影响 Bean 定义解析 |
| 与 Spring Boot | SpringApplication 围绕其实现自动化配置 |
最终建议 :
理解
ConfigurableApplicationContext的工作机制,是掌握 Spring 容器启动原理、实现高级定制(如多上下文、热部署)的基础。在实际开发中,应善用其提供的生命周期钩子和配置能力,构建健壮、可维护的应用架构。