記一次實現ApplicationContextInitializer的方法(SpringBoot)

最近再看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之前,加載好配置文件等信息功能。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章