Spring控制Bean加載順序的操作方法
前言
正常情況下,Spring 容器加載 Bean 的順序是不確定的,那么我們?nèi)绻枰错樞蚣虞d Bean 時應如何操作?本文將詳細講述我們?nèi)绾尾拍芸刂?Bean 的加載順序。
場景
我創(chuàng)建了 4 個 Class 文件,分別命名為
- FirstInitialization
- SecondInitialization
- ThirdInitialization
- ForthInitialization
我希望這 4 個類按照 1、2、3、4 的順序加載。
如下圖,直接加載的話,順序是 1、4、2、3,并不能達到要求。
如何控制
注意:網(wǎng)上很多文章說
Order
注解或Ordered
接口可以控制 Bean 的加載順序,其是并不能,它們的作用是定義 Spring IOC 容器中 Bean 定義類的執(zhí)行順序的優(yōu)先級,并不是定義加載順序。
使用@DependsOn 注解
在需要調(diào)整順序的類上依次加@DependsOn
注解,缺點是類過多的時候需要一個個加注解,且不好維護。
@Component public class FirstInitialization { @PostConstruct public void init(){ System.out.println("我是第一個加載!"); } }
@Component @DependsOn("firstInitialization") public class SecondInitialization { @PostConstruct public void init(){ System.out.println("我是第二個加載!"); } }
@Component @DependsOn("secondInitialization") public class ThirdInitialization { @PostConstruct public void init(){ System.out.println("我是第三個加載!"); } }
@Component @DependsOn("thirdInitialization") public class ForthInitialization { @PostConstruct public void init(){ System.out.println("我是第四個加載!"); } }
執(zhí)行結(jié)果如下
基于 ApplicationContextInitializer 接口
接口簡介
這里我簡單介紹一個這個接口的用處, 等到整理到相關源碼的時候再詳細介紹。
ApplicationContextInitializer
接口是在 Spring 容器刷新之前執(zhí)行的一個回調(diào)函數(shù)。
執(zhí)行時機:
Spring 內(nèi)部執(zhí)行
ConfigurableApplicationContext#refresh()
方法前;SpringBoot 執(zhí)行
run()
方法前。
一般有什么用呢?
在 SpringBoot 應用中 Classpath 上會有很多 jar 包,有些 jar 包需要在refresh()
調(diào)用前對應用上下文做一些初始化動作,因此會提供ApplicationContextInitializer
接口的實現(xiàn)類,放在如下圖的文件中,這樣會被SpringApplication#initialize
發(fā)現(xiàn),然后完成對應初始化。
實現(xiàn)步驟
首先創(chuàng)建一個類繼承ApplicationContextInitializer
接口。
public class MyApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext applicationContext) { //將自定義的BeanFactoryPostProcessor實現(xiàn)類保存到ApplicationContext中 applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor()); } }
創(chuàng)建META-INF/spring.factories
文件。
自定義BeanDefinitionRegistryPostProcessor
。
/** * BeanFactoryPostProcessor的子類 * 允許開發(fā)人員在Bean定義注冊之前和之后對BeanDefinition進行自定義處理,例如添加,修改或刪除Bean定義等。 */ public class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor { // 初始化需要排序的類,這里要保證插入順序只能用LinkedHashMap private static final Map<String, Class> ORDER_BEAN_MAP = new LinkedHashMap<>() { { put("firstInitialization", FirstInitialization.class); put("secondInitialization", SecondInitialization.class); put("thirdInitialization", ThirdInitialization.class); put("forthInitialization", ForthInitialization.class); } }; @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { Optional.ofNullable(ORDER_BEAN_MAP.keySet()).orElse(new HashSet<>()).stream() .forEach(beanName -> { // 初始化一個 Bean 定義 AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder .genericBeanDefinition().getBeanDefinition(); // 按順序注冊每個Bean beanDefinition.setBeanClass(ORDER_BEAN_MAP.get(beanName)); registry.registerBeanDefinition(beanName, beanDefinition); }); } }
執(zhí)行結(jié)果如下
以上就是Spring控制Bean加載順序的操作方法的詳細內(nèi)容,更多關于Spring控制Bean加載順序的資料請關注腳本之家其它相關文章!
相關文章
shiro并發(fā)人數(shù)登錄控制的實現(xiàn)代碼
在做項目中遇到這樣的需求要求每個賬戶同時只能有一個人登錄或幾個人同時登錄,如果是同時登錄的多人,要么不讓后者登錄,要么踢出前者登錄,怎么實現(xiàn)這樣的功能呢?下面小編給大家?guī)砹藄hiro并發(fā)人數(shù)登錄控制的實現(xiàn)代碼,一起看看吧2017-09-09Spring cloud alibaba之Ribbon負載均衡實現(xiàn)方案
Spring cloud Ribbon是基于Netflix Ribbon實現(xiàn)的一套客戶端的負載均衡工具,Ribbon客戶端提供一系列完善的配置,如超時、重試等,Ribbon也可以實現(xiàn)自己的負載均衡算法,感興趣的朋友跟隨小編一起看看吧2021-07-07SpringCloud微服務調(diào)用丟失請求頭的問題及解決方案
在Spring Cloud 中微服務之間的調(diào)用會用到Feign,但是在默認情況下,Feign 調(diào)用遠程服務存在Header請求頭丟失問題,下面給大家分享SpringCloud微服務調(diào)用丟失請求頭的問題及解決方案,感興趣的朋友一起看看吧2024-02-02Java實現(xiàn)上傳和下載功能(支持多個文件同時上傳)
這篇文章主要介紹了Java實現(xiàn)上傳和下載功能,支持多個文件同時上傳,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-12-12Java算法之BFS,DFS,動態(tài)規(guī)劃和貪心算法的實現(xiàn)
廣度優(yōu)先搜索(BFS)和深度優(yōu)先搜索(DFS)是圖遍歷算法中最常見的兩種算法,主要用于解決搜索和遍歷問題。動態(tài)規(guī)劃和貪心算法則用來解決優(yōu)化問題。本文就來看看這些算法的具體實現(xiàn)吧2023-04-04java 下執(zhí)行mysql 批量插入的幾種方法及用時
java 下執(zhí)行mysql 批量插入的幾種方法及用時,1000次插入方法的比較。2013-04-04