使用Spring @DependsOn控制bean加載順序的實(shí)例
spring容器載入bean順序是不確定的,spring框架沒有約定特定順序邏輯規(guī)范。但spring保證如果A依賴B(如beanA中有@Autowired B的變量),那么B將先于A被加載。但如果beanA不直接依賴B,我們?nèi)绾巫孊仍先加載呢?
控制bean初始化順序
可能有些場景中,bean A 間接依賴 bean B。如Bean B應(yīng)該需要更新一些全局緩存,可能通過單例模式實(shí)現(xiàn)且沒有在spring容器注冊,bean A需要使用該緩存;因此,如果bean B沒有準(zhǔn)備好,bean A無法訪問。
另一個(gè)場景中,bean A是事件發(fā)布者(或JMS發(fā)布者),bean B (或一些) 負(fù)責(zé)監(jiān)聽這些事件,典型的如觀察者模式。我們不想B 錯(cuò)過任何事件,那么B需要首先被初始化。
簡言之,有很多場景需要bean B應(yīng)該被先于bean A被初始化,從而避免各種負(fù)面影響。我們可以在bean A上使用@DependsOn注解,告訴容器bean B應(yīng)該先被初始化。下面通過示例來說明。
示例說明
示例通過事件機(jī)制說明,發(fā)布者和監(jiān)聽者,然后通過spring配置運(yùn)行。為了方便說明,示例進(jìn)行了簡化。
EventManager.java
事件管理類,維護(hù)監(jiān)聽器列表,通過單例方法獲取事件管理器,可以增加監(jiān)聽器或發(fā)布事件。
import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; public class EventManager { private final List<Consumer<String>> listeners = new ArrayList<>(); private EventManager() { } private static class SingletonHolder { private static final EventManager INSTANCE = new EventManager(); } public static EventManager getInstance() { return SingletonHolder.INSTANCE; } public void publish(final String message) { listeners.forEach(l -> l.accept(message)); } public void addListener(Consumer<String> eventConsumer) { listeners.add(eventConsumer); } }
EventPublisherBean.java
事件發(fā)布類,通過EventManager類發(fā)布事件。
import com.logicbig.example.EventManager; public class EventPublisherBean { public void initialize() { System.out.println("EventPublisherBean initializing"); EventManager.getInstance().publish("event published from EventPublisherBean"); } }
EventListenerBean.java
事件監(jiān)聽者,可以增加監(jiān)聽器。
import com.logicbig.example.EventManager; public class EventListenerBean { private void initialize() { EventManager.getInstance(). addListener(s -> System.out.println("event received in EventListenerBean : " + s)); } }
AppConfig.java
配置運(yùn)行類。
@Configuration @ComponentScan("com.logicbig.example") public class AppConfig { @Bean(initMethod = "initialize") @DependsOn("eventListener") public EventPublisherBean eventPublisherBean () { return new EventPublisherBean(); } @Bean(name = "eventListener", initMethod = "initialize") // @Lazy public EventListenerBean eventListenerBean () { return new EventListenerBean(); } public static void main (String... strings) { new AnnotationConfigApplicationContext(AppConfig.class); } }
運(yùn)行AppConfig的main方法,輸出結(jié)果為:
EventListenerBean initializing
EventPublisherBean initializing
event received in EventListenerBean : event published from EventPublisherBean
總結(jié)
如果我們注釋掉@DependsOn("eventListener"),我們可能不確定獲得相同結(jié)果。嘗試多次運(yùn)行main方法,偶爾我們將看到EventListenerBean 沒有收到事件。為什么是偶爾呢?因?yàn)槿萜鲉舆^程中,spring按任意順序加載bean。
那么當(dāng)不使用@DependsOn可以讓其100%確定嗎?可以使用@Lazy注解放在eventListenerBean ()上。因?yàn)镋ventListenerBean在啟動階段不加載,當(dāng)其他bean需要其時(shí)才加載。這次我們僅EventListenerBean被初始化。
EventPublisherBean initializing
現(xiàn)在從新增加@DependsOn,也不刪除@Lazy注解,輸出結(jié)果和第一次一致,雖然我們使用了@Lazy注解,eventListenerBean在啟動時(shí)仍然被加載,因?yàn)锧DependsOn表明需要EventListenerBean。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決rocketmq-client查詢手動發(fā)送消息異常問題
這篇文章主要介紹了解決rocketmq-client查詢手動發(fā)送消息異常問題,具有很好的參考價(jià)值,希望對大家大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08Java中Map與JSON數(shù)據(jù)之間的互相轉(zhuǎn)化
我們在開發(fā)中難免和JSON打交道,這不小編最近遇到了,需要把一些信息轉(zhuǎn)成JSON字符串,下面這篇文章主要給大家介紹了關(guān)于Java中Map與JSON數(shù)據(jù)之間的互相轉(zhuǎn)化,需要的朋友可以參考下2023-04-04Java多線程連續(xù)打印abc實(shí)現(xiàn)方法詳解
這篇文章主要介紹了Java多線程連續(xù)打印abc實(shí)現(xiàn)方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03IDEA?Debug過程中使用Drop?Frame或Reset?Frame實(shí)現(xiàn)操作回退的方法
在IDEA中就提供了一個(gè)幫助你回退代碼的機(jī)會,但這個(gè)方法并不是萬能的,好了,下面就來具體說說IDEA?Debug過程中使用Drop?Frame或Reset?Frame實(shí)現(xiàn)操作回退的方法,感興趣的朋友一起看看吧2022-04-04Spring?Data?Redis切換底層Jedis和Lettuce實(shí)現(xiàn)源碼解析
這篇文章主要為大家介紹了Spring?Data?Redis切換底層Jedis和Lettuce實(shí)現(xiàn)方法源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11java實(shí)現(xiàn)裝飾器模式(Decorator Pattern)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)裝飾器模式Decorator Pattern,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10SpringBoot修改內(nèi)置tomcat版本的操作步驟
生產(chǎn)環(huán)境使用的外部部署Tomcat還是內(nèi)置Tomcat由于版本安全漏洞,往往需要升級到指定的安全版本,本文演示一下SpringBoot升級內(nèi)置的Tomcat版本,感興趣的小伙伴跟著小編一起來看看吧2024-07-07Java中notify()和notifyAll()的使用區(qū)別
本文主要介紹了Java中notify()和notifyAll()的使用區(qū)別,文中通過示例代碼介紹的非常詳細(xì),感興趣的小伙伴們可以參考一下2021-06-06