《Spring Boot 源碼學習系列》
BootstrapRegistry 初始化器實現
- 一、引言
- 二、往期內容
- 三、主要內容
- 3.1 BootstrapRegistry
- 3.2 BootstrapRegistryInitializer
- 3.3 BootstrapRegistry 初始化器實現
- 3.3.1 定義 DemoBootstrapper
- 3.3.2 添加 DemoBootstrapper
- 四、總結
一、引言
前面的博文《BootstrapRegistryInitializer 詳解》,Huazie 帶大家一起詳細分析了 Spring Boot 啟動時加載并初始化 BootstrapRegistryInitializer
及其相關的類的邏輯。本篇就讓我們自定義 BootstrapRegistryInitializer
接口實現,以此來執行自定義的初始化操作【如注冊自定義的 Bean、添加 BootstrapContext 關閉監聽器】。
二、往期內容
在開始本篇的內容介紹之前,我們先來看看往期的系列文章【有需要的朋友,歡迎關注系列專欄】:
Spring Boot 源碼學習 |
Spring Boot 項目介紹 |
Spring Boot 核心運行原理介紹 |
【Spring Boot 源碼學習】@EnableAutoConfiguration 注解 |
【Spring Boot 源碼學習】@SpringBootApplication 注解 |
【Spring Boot 源碼學習】走近 AutoConfigurationImportSelector |
【Spring Boot 源碼學習】自動裝配流程源碼解析(上) |
【Spring Boot 源碼學習】自動裝配流程源碼解析(下) |
【Spring Boot 源碼學習】深入 FilteringSpringBootCondition |
【Spring Boot 源碼學習】OnClassCondition 詳解 |
【Spring Boot 源碼學習】OnBeanCondition 詳解 |
【Spring Boot 源碼學習】OnWebApplicationCondition 詳解 |
【Spring Boot 源碼學習】@Conditional 條件注解 |
【Spring Boot 源碼學習】HttpEncodingAutoConfiguration 詳解 |
【Spring Boot 源碼學習】RedisAutoConfiguration 詳解 |
【Spring Boot 源碼學習】JedisConnectionConfiguration 詳解 |
【Spring Boot 源碼學習】初識 SpringApplication |
【Spring Boot 源碼學習】Banner 信息打印流程 |
【Spring Boot 源碼學習】自定義 Banner 信息打印 |
【Spring Boot 源碼學習】BootstrapRegistryInitializer 詳解 |
【Spring Boot 源碼學習】ApplicationContextInitializer 詳解 |
【Spring Boot 源碼學習】ApplicationListener 詳解 |
【Spring Boot 源碼學習】SpringApplication 的定制化介紹 |
【Spring Boot 源碼學習】BootstrapRegistry 詳解 |
【Spring Boot 源碼學習】深入 BootstrapContext 及其默認實現 |
三、主要內容
注意: 以下涉及 Spring Boot 源碼 均來自版本 2.7.9,其他版本有所出入,可自行查看源碼。
3.1 BootstrapRegistry
在《BootstrapRegistry 詳解》 中,Huazie 詳細介紹了 BootstrapRegistry
的源碼,這有助于下面介紹的 BootstrapRegistry
初始化器的實現邏輯,有不知道的朋友們直接查看即可,這里不再贅述。
3.2 BootstrapRegistryInitializer
在《BootstrapRegistryInitializer 詳解》 中,Huazie 詳解分析了加載并初始化 BootstrapRegistryInitializer
的邏輯,這同樣有助于
理解下面將要講解的內容,還不熟悉的朋友們趕緊花點時間了解下,這里不再贅述。
3.3 BootstrapRegistry 初始化器實現
3.3.1 定義 DemoBootstrapper
下面我們來定義一個類 DemoBootstrapper
,該類實現 BootstrapRegistryInitializer
接口,如下:
public class DemoBootstrapper implements BootstrapRegistryInitializer {@Overridepublic void initialize(BootstrapRegistry registry) {// 注冊一些自定義的對象 或者 加載自定義的一些配置}
}
在《BootstrapRegistryInitializer 詳解》 的 3.2 小節,Huazie 介紹了 BootstrapRegistryInitializer
的加載過程,上述我們自定義的 DemoBootstrapper
也會在 Spring Boot 啟動引導階段進行加載并初始化。
上述定義中,我們只是展示了一個空實現的類,其中的 initialize
方法還未做處理。
至于 initialize
方法中該添加哪些邏輯,這就要看它的參數 BootstrapRegistry
接口了。
下面代碼,Huazie 演示了如何 注冊自定義的對象,以及添加 引導上下文關閉事件監聽器。
// 注冊 User對象,它就是一個簡單的 POJO 類,含兩個成員變量:名稱 name 和年齡 age
registry.register(User.class, context -> new User("Huazie", 18));
// 添加 BootstrapContext關閉 監聽器
registry.addCloseListener(new DemoBootstrapContextClosedListener());
DemoBootstrapContextClosedListener
,即引導上下文關閉事件監聽器,相關演示代碼如下:
public class DemoBootstrapContextClosedListener implements ApplicationListener<BootstrapContextClosedEvent>, Ordered {@Overridepublic void onApplicationEvent(BootstrapContextClosedEvent event) {BootstrapContext bootstrapContext = event.getBootstrapContext();if (bootstrapContext.isRegistered(User.class)) {System.out.println("BootstrapContext關閉時獲取User:" + bootstrapContext.get(User.class));}}@Overridepublic int getOrder() {return 1;}
}
雖然上面添加了引導上下文關閉事件監聽器,但是我們還不知道什么時候它會被執行。
在 DemoBootstrapContextClosedListener
中,我們看到了 BootstrapContext
的使用,顯然這里涉及到了引導上下文的實際使用場景,由于篇幅受限,將在下篇介紹,大家不妨期待一下。
另外,在 DemoBootstrapContextClosedListener
中,還看到它實現了 Ordered
接口【spring-core 包中的接口】。
那么在事件監聽器中,這個 Ordered
接口是用來做什么的呢?
在回答這個問題之前,我們先來看看 Ordered
接口的源碼:
public interface Ordered {int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;int LOWEST_PRECEDENCE = Integer.MAX_VALUE;int getOrder();
}
Ordered
接口定義了兩個常量和一個方法:
HIGHEST_PRECEDENCE
:最高優先級值的有用常數【最小的Integer
值】LOWEST_PRECEDENCE
:最低優先級值的有用常數【最大的Integer
值】int getOrder()
:獲取當前對象的優先級值【值越小,優先級越高】
源碼中對于 Ordered
接口是這樣說的:
它可以被需要排序的對象實現,例如在集合中。實際的排序可以被解讀為優先級排序,其中第一個對象(即有著最低的排序值)具有最高的優先級。
當然,Ordered
接口還有一個擴展接口,即優先級標記接口 PriorityOrdered
。PriorityOrdered
對象總是優先于普通 Ordered
對象,無論它們的排序值如何。當對一組 Ordered
對象進行排序時,PriorityOrdered
對象和普通 Ordered
對象實際上被視為兩個獨立的子集,PriorityOrdered
對象子集先于普通 Ordered
對象子集,并在這些子集內部應用相對排序。
上述排序邏輯請查看 spring-core 包中的 AnnotationAwareOrderComparator
類 和 OrderComparator
類,這里不再贅述了。
現在可以回答上面的問題了:在事件監聽器中實現 Ordered
接口,可以用來確保 多個監聽同一事件的監聽器 可以按照我們 預定的順序執行。
3.3.2 添加 DemoBootstrapper
不過,要想能夠加載到自定義的 DemoBootstrapper
,我們還需要將它添加到 bootstrapRegistryInitializers
中才可以。
// SpringApplication的私有變量
private List<BootstrapRegistryInitializer> bootstrapRegistryInitializers;
那么,我們該如何添加呢?
通過閱讀 SpringApplication
的源碼,可以總結如下的兩種方式:
-
在
META-INF/spring.factories
中添加org.springframework.boot.BootstrapRegistryInitializer
的配置。這種方式,我們從 《BootstrapRegistryInitializer 詳解》 的 3.2 小節可見一斑。org.springframework.boot.BootstrapRegistryInitializer=com.example.demo.DemoBootstrapper
-
通過
SpringApplication
中的addBootstrapRegistryInitializer
方法添加。其實這里在筆者的《SpringApplication 的定制化介紹》中的 1.5 小節也提及過。SpringApplication springApplication = new SpringApplication(DemoApplication.class); springApplication.addBootstrapRegistryInitializer(new DemoBootstrapper()); // 其他省略。。。
四、總結
本篇 Huazie 介紹了如何自定義 BootstrapRegistry
初始化器實現,其中演示如何在引導上下文中注冊了自定義的對象以及如何在引導上下文中添加引導上下文關閉事件監聽器。