最近再看SpringBoot的源碼,在調用refreshContext(context)之前,會對ApplicationContextInitializer的實現類等進行調用.所以寫一篇文章來進行記錄
話不多話,先上代碼,當然這裏直接實現,在SpringBoot並不會啓動,我們採用第一種方式來指定
No 1 :
package com.yang.threadspringcase.initializer;
/*
*@author:BaoYang
*@Date: 2020/2/26
*@description:
*/
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;
public class FirstInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
{
@Override
public void initialize(ConfigurableApplicationContext applicationContext)
{
ConfigurableEnvironment contextEnvironment = applicationContext.getEnvironment();
// contextEnvironment.setRequiredProperties("yang");
Map<String,Object> map = new HashMap<>();
map.put("key1","value1");
MapPropertySource mapPropertySource = new MapPropertySource("firstInitializer",map);
contextEnvironment.getPropertySources().addLast(mapPropertySource);
System.out.println("FirstInitializer Add ....");
}
}
這裏我們在resources下面,創建一個META-INF目錄,
org.springframework.context.ApplicationContextInitializer=com.yang.threadspringcase.initializer.FirstInitializer
然後使用這句話來指定即可,這是第一種配置方式.
No 2 : 第二個我們還是回繼續實現 ApplicationContextInitializer接口.
package com.yang.threadspringcase.initializer;
/*
*@author:BaoYang
*@Date: 2020/2/29
*@description:
*/
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;
public class SecondInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
{
@Override
public void initialize(ConfigurableApplicationContext applicationContext)
{
ConfigurableEnvironment environment = applicationContext.getEnvironment();
Map<String,Object> map = new HashMap<>();
map.put("key2", "value2");
MapPropertySource mapPropertySource = new MapPropertySource("secondInitializer", map);
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("SecondInitializer Init Over");
}
}
當然也需要指定一下, 這回指定類的地方,我們換一下,在application.properties中
在 application.properties中
context.initializer.classes=com.yang.threadspringcase.initializer.SecondInitializer
使用這句來指定即可.
No 3 這裏來第三種. 依然還是實現同樣的接口
package com.yang.threadspringcase.initializer;
/*
*@author:BaoYang
*@Date: 2020/2/29
*@description:
*/
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;
public class ThreeInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
{
@Override
public void initialize(ConfigurableApplicationContext applicationContext)
{
ConfigurableEnvironment environment = applicationContext.getEnvironment();
Map<String,Object> map = new HashMap<>();
map.put("key3", "value3");
MapPropertySource mapPropertySource = new MapPropertySource("threeInitializer", map);
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("ThreeInitializer Init Over");
}
}
這回就直接加在代碼裏面來實現
SpringApplication springApplication = new SpringApplication(ThreadSpringCaseApplication.class);
springApplication.addInitializers(new ThreeInitializer());
ConfigurableApplicationContext context = springApplication.run(args);
String key3 = context.getEnvironment().getProperty("key3");
System.out.println(key3);
將啓動的類修改爲這樣,第三種方式就可以了。
然後,我們啓動一下項目就可以看到相應的效果了
然後就可以看到,三句胡亂打印的Log。細心的朋友就不難猜出,Initializer的加載順序了,先從 application.properties中加載,再從META-INF/配置下加載 , 再從代碼中add中加載.
我們再來debug看看.
直接將斷點打在 SpringApplication ---> 314行, 如下的方法上
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
然後debug啓動,發現並沒有打印 Initializer 中的內容
debug到 SpringApplication 621行
applyInitializers(ConfigurableApplicationContext context) ---> getInitializers()
這個就可以看到 initializers中已經有的Initialzers實現類信息,但是自信看下來,居然沒有SecoedInitialzer的信息。然後debug一步一步的看.
當我們debug第一個
DelegatingApplicationContextInitializer.initialize() ---> getInitializerClasses(environment)
這個方面從之前的環境加載之中加載從配置文件中配置的信息, 然後繼續調用 SecondInitializer 中的 initialize方法
走完這個方法就可以看到控制輸出 SecondInitializer Init Over 這句話
然後九個中的第一個走完,然後回一次走完剩下的八個.
這裏分析完了,就可以看到SpringBoot源碼再執行Initializer的實現類執行過程。然後跟我們的打印順序一起關聯起來就即可。
由於我目前很少使用 ApplicationContextInitializer 來加載東西,所以對於深入進去的內容並不是很瞭解。
目前瞭解的一般這樣配置會在初始化Bean之前,加載好配置文件等信息功能。