1、Spring Boot 系統初始化器
系統初始化器介紹
SpringFactoriesLoader介紹
系統初始化器原理
2、系統初始化器介紹
類名: ApplicationContextinitializer
介紹: Spring容量刷新之前執行的一個回調函數
作用: 向SpringBoot容器中注冊屬性
使用:繼承接口自定義實現
3、系統初始化器實踐
創建系統初始化器方式一(實現原理:定義在spring.factories 文件中被SpringFactoriesLoader發現注冊)
1)創建初始化器
在包initializer下創建FirstInitializer
/** * * 第一個系統初始化器 */ @Order(1) public class FirstInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext applicationContext) { ConfigurableEnvironment environment = applicationContext.getEnvironment(); Map<String, Object> map = new HashMap<>(); map.put("key1","value1"); MapPropertySource mapPropertySource = new MapPropertySource("firstInitializer", map); environment.getPropertySources().addLast(mapPropertySource); System.out.println("run FirstInitializer"); } }
2) 創建spring.factories
內容為:
org.springframework.context.ApplicationContextInitializer=com.example.demo.initialize.FirstInitializer
3) 創建服務類 TestService
@Component public class TestService implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public String test(){ return applicationContext.getEnvironment().getProperty("key1"); } }
4) 在Controller層增加方法
@RequestMapping("/test") @ResponseBody public String test(){ return testService.test(); }
5) 啟動工程查看效果
可以發現打印了run FirstInitializer
然后調用接口。返回值為之前設置的value1
創建系統初始化器方式二(實現原理:初始化完畢手動添加)
1)訂單創建初始化器
@Order(2) 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("run SecondInitializer"); } }
2) SB2Application改成如下
@SpringBootApplication @MapperScan("com.example.demo.mapper") public class Sb2Application { public static void main(String[] args) { //SpringApplication.run(Sb2Application.class, args); SpringApplication springApplication = new SpringApplication(Sb2Application.class); springApplication.addInitializers(new SecondInitializer()); springApplication.run(args); } }
3) 修改Service的test方法
public String test(){ return applicationContext.getEnvironment().getProperty("key2"); }
4)啟動(說明兩個初始化器都已經創建)
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.6.RELEASE)
run FirstInitializer
run SecondInitializer
5)、測試返回結果。返回value2
創建系統初始化器方式三(實現原理:定義成環境變量被DelegatingApplicationContextInitializer發現注冊)
1)創建初始化器
@Order(3) public class ThirdInitializer 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("thirdInitializer", map); environment.getPropertySources().addLast(mapPropertySource); System.out.println("run ThirdInitializer"); } }
2) 在application.properties 增加
context.initializer.classes=com.example.demo.initializer.ThirdInitializer
3)、修改TestServer的test方法
public String test(){ return applicationContext.getEnvironment().getProperty("key3"); }
4) 啟動測試
可以發現打印的順序和定義的不一致。第三個ThirdInitializer初始化器優先於第一個和第二個打印出來。
使用接口測試,返回value2
那springboot初始化器是如何被識別呢,靠的就是SpringFactoriesLoader
springboot初始化器原理:
初始化SpringApplication 工廠加載機制 SpringFactoriesLoader
調用run方法: Spring Boot 系統初始化器是如何被調用的,以及實現原理