首頁  >  文章  >  Java  >  SpringBoot容器刷新前怎麼回呼ApplicationContextInitializer

SpringBoot容器刷新前怎麼回呼ApplicationContextInitializer

WBOY
WBOY轉載
2023-05-11 08:58:111001瀏覽

I. 專案準備

本文所建立的實例工程採用SpringBoot 2.2.1.RELEASE maven 3.5.3 idea進行開發

具體的SpringBoot專案工程創建就不贅述了,核心的pom文件,無需額外的依賴

配置文件application.yml, 也沒有什麼特殊的配置

II. 容器刷新前擴展點實例

1. 自訂ApplicationContextInitializer

當我們希望實作一個自訂的上下文初始化時,非常簡單,實作上面這個接口就行了,如

public class ApplicationContextInitializer01 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("ApplicationContextInitializer01");
    }
}

2. 擴充點註冊

上面自訂一個擴充點,如何使它生效呢?

官方提供了三種方式,如在啟動時,直接進行註冊: springApplication.addInitializers(new ApplicationContextInitializer01());

#
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(Application.class);
        springApplication.addInitializers(new ApplicationContextInitializer01());
        try (ConfigurableApplicationContext context = springApplication.run(args)) {
        }
    }
}

當我們的擴展點是放在一個jar包中對外提供時,使用上面的啟動註冊方式顯然是不可行的,此時更推薦的做法就是透過Spring的SPI機制進行註冊

在資源目錄下的META-INF/spring.factories檔案中進行註冊

org.springframework.context.ApplicationContextInitializer=com.git.hui.extention.context.ApplicationContextInitializer02

#說明

  • 上面SPI的機制非常推薦大家使用,在先前的文章中,AutoConfiguration的註冊通常也是使用這種方式

除了上面的兩種註冊方式之外,另外還有一個設定檔的方式,在設定檔application.propertiesapplication.yml中,如下設定

context:
  initializer:
    classes: com.git.hui.extention.context.ApplicationContextInitializer03

啟動測試

#上面三種註冊方式,我們實作三個自訂的擴充點,然後啟動之後,看一下實際輸出

SpringBoot容器刷新前怎麼回呼ApplicationContextInitializer

#上面的輸出,可以簡單的得出一個結論,不同註冊方式的優先順序(為了更合理的驗證下面的觀點,推薦大家修改下上面三個自訂擴充點名,排除掉是因為副檔名導致的排序問題)

  • 設定檔註冊> SPI註冊> 啟動時註冊

3. 執行順序指定

#對於自訂的擴充點實現,當存在順序關係時,我們可以透過@Order註解來實現, 如當上面的三個擴展點都是透過啟動方式註冊時

@Order(5)
public class ApplicationContextInitializer01 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("ApplicationContextInitializer01");
    }
}

@Order(2)
public class ApplicationContextInitializer02 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("ApplicationContextInitializer02");
    }
}

@Order(10)
public class ApplicationContextInitializer03 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("ApplicationContextInitializer03");
    }
}

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(Application.class);
        springApplication.addInitializers(new ApplicationContextInitializer01(), new ApplicationContextInitializer02(), new ApplicationContextInitializer03());
        try (ConfigurableApplicationContext context = springApplication.run(args)) {
        }
    }
}

輸出實例如下

SpringBoot容器刷新前怎麼回呼ApplicationContextInitializer

接著重點來了

  • 若上面的三個自訂實現,不是相同的註冊方式,如將03採用設定檔方式進行註冊,那麼01, 02 還是啟動註冊

  • 則順序是03 > 02 > 01

  • @Order 註解修飾的順序,並不能打破設定檔> SPI > 啟動方式註冊的順序

關於自訂實作類別的執行順序,規則如下

  • 設定檔> SPI > 啟動方式

  • #相同的註冊方式,可以透過@Order註解進行修飾,值越小則優先權越高

4. 使用場景範例

最後我們再來看一下,這個擴充點到底有什麼用,我們再什麼場景下會用到這個呢?

一個經常可以看到的應用場景如透過它來指定需要啟動的設定檔

public class ApplicationContextInitializer03 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        // 指定激活prod对应的配置文件
        configurableApplicationContext.getEnvironment().setActiveProfiles("prod");
    }
}

但是一般也很少見到有人這麼做,因為直接使用設定參數就行了,那麼有場景需要這麼做麼?

答案當然是有的,例如現在廣為流行的docker容器部署,當我們希望每次都是打同一個鏡像,然後在實際運行的時候,根據不同的環境來決定當前鏡像到底啟用哪些配置文件,這時就有用了

例如我們通過容器的環境參數app.env 來獲取當前運行的環境,如果是prod,則激活application- prod.yml; 如果是test,則啟動application-test.yml

#那麼此時可以這麼幹

public class EenvActiveApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        String env = System.getenv("app.env");
        if ("prod".equalsIgnoreCase(env)) {
            configurableApplicationContext.getEnvironment().setActiveProfiles("prod");
        } else if ("test".equalsIgnoreCase(env)) {
            configurableApplicationContext.getEnvironment().setActiveProfiles("test");
        } else {
            throw new RuntimeException("非法的环境参数:" + env);
        }
    }
}

以上是SpringBoot容器刷新前怎麼回呼ApplicationContextInitializer的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除