使用監(jiān)聽(tīng)器對(duì)Spring bean id進(jìn)行唯一校驗(yàn)過(guò)程解析
背景
項(xiàng)目中用到了多數(shù)據(jù)源,不同的數(shù)據(jù)源根據(jù)業(yè)務(wù)不同配置在不同的工程中,由maven來(lái)統(tǒng)一聚合。但是前幾天在開(kāi)發(fā)過(guò)程中突然發(fā)現(xiàn)項(xiàng)目前臺(tái)工程的事務(wù)配置不起作用了,在之前明明測(cè)試過(guò)事務(wù)功能,當(dāng)時(shí)是生效的。
然后檢查了一下配置文件中事務(wù)部分的配置,發(fā)現(xiàn)沒(méi)什么改動(dòng)。為了排除其它因素的干擾,采用了單元測(cè)試重新測(cè)試了一次,結(jié)果發(fā)現(xiàn)當(dāng)前數(shù)據(jù)源事務(wù)正常。根據(jù)這個(gè)分析可能是當(dāng)前的事務(wù)配置被其它配置干擾了,仔細(xì)檢查了一下后發(fā)現(xiàn)罪魁禍?zhǔn)资橇硗獾囊粋€(gè)數(shù)據(jù)源事務(wù)配置(在另外的一個(gè)配置文件中)的bean id名稱(chēng)和當(dāng)前的事務(wù)配置bean id重復(fù)了。
我們都知道,Spring會(huì)對(duì)同一份配置文件中的bean進(jìn)行校驗(yàn),也就是說(shuō)在同一份配置文件中不允許出現(xiàn)相同的bean定義,會(huì)提示報(bào)錯(cuò)。但是Spring IOC容器在加載時(shí)并不會(huì)顯示對(duì)不同配置文件中重復(fù)的bean id進(jìn)行報(bào)錯(cuò)提示,當(dāng)遇到有重復(fù)的bean定義時(shí),Spring采取的策略是把后面加載的配置覆蓋前面加載的配置,沒(méi)有任何警告和提示。
這樣很容易造成一個(gè)問(wèn)題是當(dāng)我們團(tuán)隊(duì)進(jìn)行開(kāi)發(fā)時(shí)可能會(huì)不小心覆蓋別人定義的bean,導(dǎo)致系統(tǒng)出現(xiàn)不可預(yù)知的錯(cuò)誤和異常。
怎么解決這個(gè)問(wèn)題呢?我們可以配置監(jiān)聽(tīng)器,在Spring容器啟動(dòng)時(shí)對(duì)重復(fù)的bean進(jìn)行校驗(yàn),如果有重復(fù)的bean,則報(bào)錯(cuò)提示。
因?yàn)镾pring IOC容器啟動(dòng)加載時(shí)會(huì)檢查bean定義是否有重復(fù),如果有重復(fù)則會(huì)根據(jù)AbstractRefreshableApplicationContext類(lèi)中的allowBeanDefinitionOverriding屬性值進(jìn)行判斷,如果值為true,則把后加載的bean覆蓋前面加載的bean定義,如果為false則拋出BeanDefinitionStoreException異常。
所以,解決這個(gè)問(wèn)題的辦法就比較簡(jiǎn)單了,只要將這個(gè)allowBeanDefinitionOverriding值在spring初始化的時(shí)候設(shè)置為false就行了。具體步驟如下:
1.自定義一個(gè)ContextLoader
/** * ClassName:MyContextLoader <br/> * Function: 自定義ContextLoader. <br/> * Date: 2013-1-18 下午03:53:16 <br/> * @author chenzhou * @version * @since JDK 1.6 */ public class MyContextLoader extends ContextLoader { /** * 設(shè)置allowBeanDefinitionOverriding屬性為false,spring ioc容器在加載bean的過(guò)程中會(huì)去判斷beanName 是否有重復(fù),. <br/> * 如果發(fā)現(xiàn)重復(fù)的話再根據(jù)allowBeanDefinitionOverriding 這個(gè)成員變量,. <br/> * 如果是false的話則拋出BeanDefinitionStoreException 這個(gè)異常,如果為true的話就會(huì)覆蓋這個(gè)bean的定義. <br/> * @see org.springframework.web.context.ContextLoader#customizeContext(javax.servlet.ServletContext, * org.springframework.web.context.ConfigurableWebApplicationContext) */ @Override protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext){ super.customizeContext(servletContext, applicationContext); XmlWebApplicationContext context = (XmlWebApplicationContext) applicationContext; //設(shè)置allowBeanDefinitionOverriding屬性為false context.setAllowBeanDefinitionOverriding(false); } }
2.自定義一個(gè)ContextLoaderListener
/** * ClassName:MyContextLoaderListener <br/> * Function: 自定義ContextLoaderListener. <br/> * Date: 2013-1-18 下午04:12:00 <br/> * @author chenzhou * @version * @since JDK 1.6 */ public class MyContextLoaderListener extends ContextLoaderListener { @Override protected ContextLoader createContextLoader(){ return new MyContextLoader(); } }
3.修改web.xml文件的監(jiān)聽(tīng)器配置
<!-- 自定義的ContextLoaderListener --> <listener> <listener-class>com.chenzhou.examples.erm.util.listener.MyContextLoaderListener</listener-class> </listener>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- spring中bean id相同引發(fā)故障的分析與解決
- Spring實(shí)戰(zhàn)之容器中的工程Bean用法示例
- Spring實(shí)戰(zhàn)之抽象Bean和子Bean定義與用法示例
- Spring實(shí)戰(zhàn)之調(diào)用實(shí)例工廠方法創(chuàng)建Bean操作示例
- Spring實(shí)戰(zhàn)之使用靜態(tài)工廠方法創(chuàng)建Bean操作示例
- Spring如何使用注解的方式創(chuàng)建bean
- Spring實(shí)戰(zhàn)之注入嵌套Bean操作示例
- Java類(lèi)獲取Spring中bean的5種方式
- Spring的自動(dòng)裝配Bean的三種方式
- Spring實(shí)戰(zhàn)之獲得Bean本身的id操作示例
相關(guān)文章
SpringBoot2 整合FreeMarker實(shí)現(xiàn)頁(yè)面靜態(tài)化示例詳解
這篇文章主要介紹了SpringBoot2 整合FreeMarker實(shí)現(xiàn)頁(yè)面靜態(tài)化示例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07基于Spark實(shí)現(xiàn)隨機(jī)森林代碼
這篇文章主要為大家詳細(xì)介紹了基于Spark實(shí)現(xiàn)隨機(jī)森林代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08在Java中實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行
這篇文章主要介紹了在Java中實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06Java深入學(xué)習(xí)圖形用戶界面GUI之事件處理
這篇文章主要介紹了基于Java GUI 事件處理方式,一個(gè)圖形界面制作完成了,在程序開(kāi)發(fā)中只是完成了起步的工作。要想讓一個(gè)組件都發(fā)揮自己的作用.就必須對(duì)所有的組件進(jìn)行事件處理2022-05-05Java 可視化垃圾回收_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Ben Evans是一名資深培訓(xùn)師兼顧問(wèn),他在演講可視化垃圾回收中從基礎(chǔ)談起討論了垃圾回收。以下是對(duì)其演講的簡(jiǎn)短總結(jié)。感興趣的朋友一起學(xué)習(xí)吧2017-05-05Java數(shù)據(jù)結(jié)構(gòu)之鏈表的增刪查改詳解
在這篇文章中,小編將帶大家了解一下Java數(shù)據(jù)結(jié)構(gòu)中鏈表的增刪查改(以下結(jié)果均在IDEA中編譯)希望在方便自己復(fù)習(xí)的同時(shí)也能幫助到大家2022-09-09Springboot項(xiàng)目編譯后未能加載靜態(tài)資源文件的問(wèn)題
這篇文章主要介紹了Springboot項(xiàng)目編譯后未能加載靜態(tài)資源文件的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08