擴(kuò)展點(diǎn)
ApplicationContextInitializer 接口用于在 Spring 容器【刷新】之前執(zhí)行的一個(gè)回調(diào)函數(shù),通常用于向 SpringBoot 容器中注入屬性。
刷新指的是 org.springframework.context.ConfigurableApplicationContext#refresh,這是Spring容器啟動(dòng)的核心,在早期Spring版本(SpringBoot之前)就已經(jīng)存在

我們打開prepareContext方法可以看到,有一個(gè)applyInitializers方法

applyInitializers從名稱上可以看出,它是應(yīng)用initializer的一個(gè)邏輯,可以看看具體的方法實(shí)現(xiàn),就是遍歷initializer集合,然后調(diào)用接口的initialize()

好了,我們現(xiàn)在知道了它的調(diào)用時(shí)機(jī),但是集合中的initializer是怎么加載進(jìn)去的呢?
加載方式
ApplicationContextInitializer有三種方式加載。
1,在 resources/META-INF/spring.factories 中配置
2,在啟動(dòng)類里調(diào)用SpringApplication類的addInitializers()方法
3,配置context.initializer.classes
方式一:

方式二:
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(HelloApplication.class);
springApplication.addInitializers(new MyApplicationInitializer());
springApplication.run(args);
}
}
方式三:
application.properties配置項(xiàng),多個(gè)用逗號(hào)分隔

加載順序
我們通過方式二和方式三配置多個(gè)自定義的initializer,啟動(dòng)可以看到SpringApplication中有多個(gè)Initializer

最后一個(gè)是MyApplicationInitializer,但是沒有看到方式三配置的2個(gè)。
我們先來看看,為什么會(huì)有8個(gè)Initializer。因?yàn)镾pringBoot框架本身定義了多個(gè)。
從spring-boot-autoconfigure.jar和spring-boot.jar中的spring.factories可以看到


也就是說SpringBoot框架本身用了方式二添加Initializer。
那方式三的2個(gè)Initializer去哪里了呢?其實(shí)方式三是一種比較隱藏的定義Initializer的方式,它是靠DelegatingApplicationContextInitializer來加載的。
從名稱上可以看出來,這個(gè)Initializer是一個(gè)Delegating,它是一個(gè)類似代理的作用。
查看它的initialize()方法可以看到,它就是讀取context.initializer.classes配置并執(zhí)行對(duì)應(yīng)的Initializer。
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
List<Class<?>> initializerClasses = this.getInitializerClasses(environment);
if (!initializerClasses.isEmpty()) {
this.applyInitializerClasses(context, initializerClasses);
}
}
private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
String classNames = env.getProperty("context.initializer.classes");
List<Class<?>> classes = new ArrayList();
if (StringUtils.hasLength(classNames)) {
String[] var4 = StringUtils.tokenizeToStringArray(classNames, ",");
int var5 = var4.length;
for(int var6 = 0; var6 < var5; ++var6) {
String className = var4[var6];
classes.add(this.getInitializerClass(className));
}
}
return classes;
}
從上面的解釋可以分析出,大致執(zhí)行順序是 DelegatingApplicationContextInitializer -> SpringBoot官方其他的Initializer -> 項(xiàng)目本身spring.factories配置的Initializer->Application啟動(dòng)類中主動(dòng)添加的Initializer
其實(shí),除了DelegatingApplicationContextInitializer(order=0) ,后面的順序可以自定義,使用Spring的Order注解。從源碼可以看到對(duì)initializers集合是做了排序的。
參考
http://www.itdecent.cn/p/6af81951fb4e
https://zhuanlan.zhihu.com/p/650183190