SpringBoot擴(kuò)展點(diǎn)-ApplicationContextInitializer

擴(kuò)展點(diǎn)

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


image.png

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


image.png

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


image.png

好了,我們現(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

方式一:


image.png

方式二:

@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)分隔


image.png

加載順序

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

image.png

最后一個(gè)是MyApplicationInitializer,但是沒有看到方式三配置的2個(gè)。

我們先來看看,為什么會(huì)有8個(gè)Initializer。因?yàn)镾pringBoot框架本身定義了多個(gè)。
從spring-boot-autoconfigure.jar和spring-boot.jar中的spring.factories可以看到


image.png
image.png

也就是說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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容