Springboot 內建ApplicationContextInitializer
阿新 • • 發佈:2018-11-19
概述
在包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.name vcap.application.name spring.config.name spring.application.index vcap.application.instance_index PORT 如果這些屬性都沒有,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 |
AutoConfigurationReportLoggingInitializer |
org.sf.boot.autoconfigure.logging |
將ConditionEvaluationReport 寫入日誌 |
注意 : 上表中包名中的
springframework
縮寫為sf