本文代码基于 Springboot 2.1.0
概述
在包org.springframework.context中提供了这样一个接口ApplicationContextInitializer :
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
/**
* 初始化给定的 application context.
* @param applicationContext 需要被初始化的 application context
*/
void initialize(C applicationContext);
}
这是一个用来初始化Spring ConfigurableApplicationContext应用上下文的回调接口,设定的调用时机是在ConfigurableApplicationContext#refresh()调用之前。
该接口典型的应用场景是web应用中需要编程方式对应用上下文做初始化。比如,注册属性源(property sources)或者针对上下文的环境信息environment激活相应的profile。
使用分析
在一个Springboot应用中,classpath上会包含很多jar包,有些jar包需要在ConfigurableApplicationContext#refresh()调用之前对应用上下文做一些初始化动作,因此它们会提供自己的ApplicationContextInitializer实现类,然后放在自己的META-INF/spring.factories属性文件中,这样相应的ApplicationContextInitializer实现类就会被SpringApplication#initialize发现:
// SpringApplication#initialize方法,在其构造函数内执行,从而确保在其run方法之前完成
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));// <===================
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
然后在应用上下文创建之后,应用上下文刷新(refresh)之前的准备阶段被调用 :
// SpringApplication#run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner); // <===================
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
// SpringApplication#prepareContext方法
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context); // <==============
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
常见的一些ApplicationContextInitializer实现
下面列出了一个使用缺省配置的springboot web应用所使用到的ApplicationContextInitializer实现:
| 实现类 | 包 | 介绍 |
|---|---|---|
DelegatingApplicationContextInitializer | org.sf.boot.context.config | 使用环境属性context.initializer.classes指定的初始化器(initializers)进行初始化工作,如果没有指定则什么都不做 |
ContextIdApplicationContextInitializer | org.sf.boot.context | 设置Spring应用上下文的ID,会参照环境属性:spring.application.namevcap.application.namespring.config.namespring.application.indexvcap.application.instance_indexPORT如果这些属性都没有,ID使用"application"。 |
ConfigurationWarningsApplicationContextInitializer | org.sf.boot.context | 对于一般配置错误在日志中作出警告 |
ServerPortInfoApplicationContextInitializer | org.sf.boot.context.embedded | 将内置servlet容器实际使用的监听端口写入到Environment环境属性中。这样属性"local.server.port"就可以直接通过@Value注入到测试中,或者通过环境属性Environment获取。 |
SharedMetadataReaderFactoryContextInitializer | org.sf.boot.autoconfigure | 创建一个SpringBoot和ConfigurationClassPostProcessor共用的CachingMetadataReaderFactory对象,实现类使用ConcurrentReferenceCachingMetadataReaderFactory |
ConditionEvaluationReportLoggingListener | org.sf.boot.autoconfigure.logging | 将ConditionEvaluationReport写入日志 |
注意 : 上表中包名中的
springframework缩写为sf
Spring Boot应用上下文初始化

本文深入探讨了Spring Boot中ApplicationContextInitializer接口的作用及其实现,解释了如何在应用上下文刷新前进行初始化,并列举了一些常见的实现类。
1015

被折叠的 条评论
为什么被折叠?



