https://zhuanlan.zhihu.com/p/344973213
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
/**
* Initialize the given application context.
* @param applicationContext the application to configure
*/
void initialize(C applicationContext);
}
#### ---------------------------------------ApplicationContextInitializer的加载和使用触发点
ApplicationContextInitializer是在Springboot启动过程(refresh方法前)调用,允许我们对ConfiurableApplicationContext的实例做进一步的设置和处理。
如PropertySourceBootstrapConfiguration类可以在其initialize方法中遍历for (PropertySourceLocator locator : this.propertySourceLocators) 配置的位置,
把配置加入到环境中。
在SpringApplication的构造函数中通过spi机制把实现了ApplicationContextInitializer的类加载进来
-> new SpringApplication()
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))
调用触发点
-> SpringApplication.run()
-> SpringApplication.prepareContext()
applyInitializers
-> SpringApplication.applyInitializers()
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);
}
}
-> PropertySourceBootstrapConfiguration.initialize()
for (PropertySourceLocator locator : this.propertySourceLocators) {
Collection<PropertySource<?>> source = locator.locateCollection(environment) NacosPropertySourceLocator把nacos配置加载进来
#### ---------------------------------------ApplicationContextInitializer实现主要有3中方式
先创建一个类实现ApplicationContextInitializer这个接口,实现对应的方法。
public class AppInit implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("\ncustom ApplicationContextInitializer is :" + applicationContext.getDisplayName());
}
}
1、使用spring.factories方式,在resource下面新建/META-INF/spring.factories文件。
org.springframework.context.ApplicationContextInitializer=\
com.yfw.learn.AppInit
2、application.properties添加配置方式:
对于这种方式是通过DelegatingApplicationContextInitializer这个初始化类中的initialize方法获取到
application.properties中context.initializer.classes对应的类并执行对应的initialize方法。
只需要将实现了ApplicationContextInitializer的类添加到application.properties即可。如下:
context.initializer.classes=com.yfw.learn.AppInit
3、在启动类修改启动方式。
SpringApplication application = new SpringApplication(TestDemoApplication.class);
application.addInitializers(new TestContextInitializer());
application.run(args);
不 过一般 情 况 下 我 们 不 需 要 自 定 义 一 个ApplicationContextInitializer,Spring Boot框架默认也只有以下实现而已:
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
ConfigurationWarningsApplicationContextInitializer 用于报告 Spring 容器的一些常见的错误配置,可以看出,
该初始化器为 context 增加了一个 Bean 的后置处理器。这个处理器是在注册 BeanDefinition 实例之后生效的,
用于处理注册实例过程中产生的告警信息,其实就是通过日志打印出告警信息。
ContextIdApplicationContextInitializer用于设置 Spring 应用上下文 ID,这个 ID 可以通过 ApplicationContext#getId() 的方式获得。
DelegatingApplicationContextInitializer 看到 Delegating 就知道了,这个初始化器是为了别人服务的。这个初始化器会获得 application.properties
下的配置为 context.initializer.classes 的值,这个值是初始化器的全路径名,多个之间用逗号隔开。获得名称后,使用反射将其实例化,
并依次触发初始化器的 initialize 方法。DelegatingApplicationContextInitializer 使得 Spring Boot 的用户可以在 application.properties 中配置初始化器。需要注意的是,DelegatingApplicationContextInitializer 的优先级是 0 ,所以不论 context.initializer.classes
配置的初始化器的 order 是多少,都会按照 0 的优先级执行。
RSocketPortInfoApplicationContextInitializer 和 ServerPortInfoApplicationContextInitializer 都是给 ApplicationContext 增加了个监听器,
二者都是监听 RSocketServerInitializedEvent 事件,为环境 Environment 中添加一个属性源,不同之处在于一个是增加 SocketPort,一个是增加 ServerPort。
除了 spring-boot 下的 META-INF/spring.factories 存在初始化器外,spring-boot-autoconfigure 下也存在 META-INF/spring.factories。这里也定义了两个初始化器。从这里也可以看出,使用 SPI 的方式确实降低了项目间的耦合,每个项目都能定义自己的实现。
org.springframework.context.ApplicationContextInitializer=
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener