1. 程式人生 > >spring bean id重複覆蓋的問題解決

spring bean id重複覆蓋的問題解決

問題:

   當我們的web應用做成一個大專案之後,裡面有很多的bean配置,如果兩個bean的配置id是一樣的而且實現類也是一樣的,例如有下面兩份xml的配置文件:

beancontext1.xml

beancontext2.xml

  

當spring容器初始化時候同時載入這兩份配置檔案到當前的上下文的時候,程式碼如下:

 執行這個程式你會看見控制檯上列印的結果是:

beancontext2

顯然,beancontext2.xml的bean的配置覆蓋了 beancontext1.xml中bean的配置,而且在spring初始化上下文的過程中這個過程是靜悄悄的執行的,連一點警告都沒有。這樣如果你的專案中定義了兩個id同名的bean,並且,他們的實現方式又是不一樣的,這樣在後期在專案中執行的邏輯看起來就會非常詭異,而且,如果有大量配置spring配置檔案的話,排查問題就會非常麻煩。

解決問題:

  那麼,我們如何來解決這個問題嗎?靠程式設計師自律?絕對不定義重複名稱的bean?我覺得這個是不靠譜的,只有通過在程式中引入一種交錯機制才能解決這個問題。

   首先,我們將上面那段程式的log4j日誌開啟,看看在spring在初始化的時候面對有兩個同名的bean是怎麼處理的。

- INFO - Refreshing org[email protected]aa9835: display name [org[email protected]aa9835]; startup date [Sat Jun 19 18:23:30 CST 2010]; root of context hierarchy
- INFO - Loading XML bean definitions from class path resource [com/koubei/samebeannameconfict/beancontext1.xml]
- DEBUG - Using JAXP provider [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl]
- DEBUG - Found beans DTD [file:///spring-beans.dtd] in classpath: spring-beans.dtd
- DEBUG - Loading bean definitions
- DEBUG - Loaded 1 bean definitions from location pattern [com/koubei/samebeannameconfict/beancontext1.xml]
- INFO - Loading XML bean definitions from class path resource [com/koubei/samebeannameconfict/beancontext2.xml]
- DEBUG - Using JAXP provider [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl]
- DEBUG - Found beans DTD [file:///spring-beans.dtd] in classpath: spring-beans.dtd
- DEBUG - Loading bean definitions
- INFO - Overriding bean definition for bean 'testbean': replacing [Generic bean: class[com.koubei.samebeannameconfict.Bean]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [com/koubei/samebeannameconfict/beancontext1.xml]] with [Generic bean: class [com.koubei.samebeannameconfict.Bean]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [com/koubei/samebeannameconfict/beancontext2.xml]]
- DEBUG - Loaded 0 bean definitions from location pattern [com/koubei/samebeannameconfict/beancontext2.xml]
- INFO - Bean factory for application context [org[email protected]aa9835]:org.s[email protected]1662dc8
- DEBUG - 1 beans defined in org[email protected]aa9835: display name [org[email protected]aa9835]; startup date [Sat Jun 19 18:23:30 CST 2010]; root of context hierarchy
- DEBUG - Unable to locate MessageSource with name 'messageSource': using default [[email protected]5f1]
- DEBUG - Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.[email protected]503429]
- INFO - Pre-instantiating singletons in org.s[email protected]1662dc8: defining beans [testbean]; root of factory hierarchy
- DEBUG - Creating shared instance of singleton bean 'testbean'
- DEBUG - Creating instance of bean 'testbean'
- DEBUG - Eagerly caching bean 'testbean' to allow for resolving potential circular references
- DEBUG - Finished creating instance of bean 'testbean'
- DEBUG - Returning cached instance of singleton bean 'testbean'

以上日誌中標紅的是關鍵,spring在處理有重名的bean的定義的時候原來是使用的覆蓋(override)的方式。我們來看看它是如何覆蓋的

在org.springframework.beans.factory.support.DefaultListableBeanFactory 這個類中有這樣一段程式碼:

		synchronized (this.beanDefinitionMap) {
			Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
			if (oldBeanDefinition != null) {
				if (!this.allowBeanDefinitionOverriding) {
					throw new BeanDefinitionStoreException(beanDefinition
							.getResourceDescription(), beanName,
							"Cannot register bean definition ["
									+ beanDefinition + "] for bean '"
									+ beanName + "': There is already ["
									+ oldBeanDefinition + "] bound.");
				} else {
					if (this.logger.isInfoEnabled()) {
						this.logger
								.info("Overriding bean definition for bean '"
										+ beanName + "': replacing ["
										+ oldBeanDefinition + "] with ["
										+ beanDefinition + "]");
					}
				}
			} else {
				this.beanDefinitionNames.add(beanName);
				this.frozenBeanDefinitionNames = null;
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
			resetBeanDefinition(beanName);
		}

     spring ioc容器在載入bean的過程中會去判斷beanName 是否有重複,如果發現重複的話在根據allowBeanDefinitionOverriding 這個成員變數,如果是false的話則丟擲BeanDefinitionStoreException 這個異常,如果為true的話就會覆蓋這個bean的定義(預設為true)。

所以,解決這個問題的辦法就比較簡單了,只要將這個allowBeanDefinitionOverriding值在spring初始化的時候設定為false就行了。

我把解決這個問題的環境放到,web工程中來:

在web工程中載入spring容器會通過:

這個listener來完成的,在這個listener中會構造 org.springframework.web.context.ContextLoader 這個構造器來載入bean

所以,只要擴充套件 ContextLoader 和ContextLoaderListener這兩個類就行了,程式碼如下:

KoubeiContextLoader:

KoubeiContextLoaderListener:

最後修改wen-inf 下web.xml 檔案,修改listener的配置,如下:

設定完這些就ok了,這樣你專案中如果在兩份被載入的xml檔案中如果再出現名字相同的bean的話,spring在載入過程中就會無情的丟擲異常,當你去除掉這個異常之後,就能重新出發了。yeah!!!!

相關推薦

spring bean id重複覆蓋的問題解決

問題:    當我們的web應用做成一個大專案之後,裡面有很多的bean配置,如果兩個bean的配置id是一樣的而且實現類也是一樣的,例如有下面兩份xml的配置文件: beancontext1.xml <?xml version="1.0" encoding="UTF

Spring bean id 重複覆蓋的問題解決

問題提問:  當我們的web應用龐大之後,裡面有很多的bean配置並且是分檔案的,如果兩個bean的配置id是一樣的而且實現類也是一樣的,例如有下面兩份xml的配置文件。 問題分析: beancontext1.xml <?xml version="1.0"

Spring Bean中迴圈依賴解決方案

在迴圈依賴是指在A中引用B,B中引用C,而C中引用A,容器建立物件時會出現死迴圈。相關解決方案如下: 1 選擇其一使其延遲載入,然後從上下文中獲取AService型別的bean即可。 現有AService 和BService,都在對方bean中注入,導致初始化時迴圈初始報錯,解決方案就是

關於quartz定時任務實現Job介面無法註解為spring bean 的一種解決方案

  通常情況下,我們使用quartz之後,定時任務實現Job介面,並重寫execute()方法: public class QuartzJob1 implements Job { /** * quartz回撥此介面,此介面中為定時任務具體執行內容 *

DUBBO配置引發的一個問題--- DUPLICATE SPRING BEAN ID

1.原因    因專案業務需要,要呼叫RPC框架,專案原本已經依賴了很多RPC介面需要啟動時載入,所以準備做成啟動時不預載入。 就是在配置的時候加上check=false.   官方文件解釋的作用,就是Dubbo 預設會在啟動時檢查依賴的服務是否可用,不可用時會丟擲異常,阻止

Duplicate spring bean id BarterUserService

1.如果是在同一個專案下搞的測試,bean名就不要重複了,可能會出現這個錯誤 2.spring id 重複吧,或者載入了2個相同的配置檔案,可能會出現這個錯誤 3.web.xml中載入的時候

使用監聽器對Spring bean id進行唯一校驗

       因為Spring IOC容器啟動載入時會檢查bean定義是否有重複,如果有重複則會根據AbstractRefreshableApplicationContext類中的allowBeanDefinitionOverriding屬性值進行判斷,如果值為true,則把

spring bean重新載入問題解決

背景: 1、tomcat工程啟動比較慢,會導致很長的一段時間無法對外提供服務。 2、伺服器數量比較多,更新一次運維會花比較長的時間。 描述: 對系統框架進行調整,把會頻繁更新的功能,做成spring jar包,放在web站點,然後tomcat上部署的系統自動向web站點請

Spring Configuration動態繫結bean id

簡述: 對於bean id 可能在注入的時候需要根據配置動態的制定例項 程式碼: ERepositoryConfigure.java package com.cpa.components.system.e.repository; import org.apache.com

Spring JPA Save()物件後返回該物件ID為0解決辦法

springdatajpa是很好用 的一個工具,但是!首先你要會用  今天下午就被一個spring-data-jpa的問題卡了略久,因為想要用MySQL自增id,想要在save之後獲取這個儲存的實體的id進行後續的工作,一直以為springdatajpa中的save方法執行結束之後,sav

Spring Bean 自動裝配 的歧義性(bean 的名稱重複)處理

在spring 中,spring 對於上下文的bean ,當自動裝配時,如果bean 的名稱相同,spring 無法做出選擇 。這就所謂的bean 自動裝配的歧義性。所以,當發現歧義性的時候,需要通過一些的方案來解決這個問題。 將可選bean 中的某個設定為首選(primary)的bea

Spring-bean的迴圈依賴以及解決方式

版權宣告:本文為博主原創文章,未經博主允許不得轉載。    https://blog.csdn.net/u010853261/article/details/77940767 本文主要是分析Spring bean的迴圈依賴,以及Spring的解決方式。 通過這種解決方式,我們

TP5:二維陣列遍歷用save()方法 ,報主鍵ID重複解決方法

$mUser = model('User'); foreach ($arrData as $k => $v) { $arrData[$k]['addtime'] = time(); $res = $mUser->isUpdate(false)->data($arr

Quartz Job類無法注入spring bean問題解決方法

問題描述: 在Quartz的任務類中,無法使用autowired注入spring bean @Component @PersistJobDataAfterExecution @DisallowConcurrentExecution publi

Spring Bean 迴圈依賴解決方案

由於service層互相呼叫,一下子沒有什麼好的拆分方案,所以先解決迴圈依賴問題。 現有AService 和BService,都在對方bean中注入,導致初始化時迴圈初始報錯,解決方案就是選擇其一使其延遲載入。 用配置方式只要將其一設定lazy-init,具

spring 配置時 bean idbean name 的區別

簡單的說:id用來標識bean,是唯一的,且只有一個;name定義的是bean的alias,可以有多個,並可能與其他的bean重名。 詳細的說: id是唯一標識bean.不能用特殊字元:×#@ ,不能用數字開頭。在bean引用的時候只能用id指向你需要的bean;

javaEE 中spring bean 重複問題

第一:在典型的基於spring bean的javaEE專案中:webmvc-config.xml中: <context:component-scan base-package="com.jingoal" use-default-filters="false">

Spring-Bean的銷燬使用destroy-method()方法無效解決方案(容器!附原始碼)

Bean package com.gc.action; import java.util.Date; public class HelloWorld { private String msg=null;//該變數用來儲存字串 private Date date=

Android自動化測試之Monkeyrunner解決ID重複問題

原文: 時光過得太快了,一晃離上一篇monkeyrunner系列的部落格已經一年多了。這一年多時間經歷了太多改變,一直沒時間好好去總結和分享。直到今天在微博上和朋友聊到monkeyrunner,才想起趁這個機會再總結一下之前所積累的一些經驗和技巧,在這裡再次和大家分享下

classpath 和 classpath* 區別以及如何覆蓋在配置檔案中的Bean ID

寫spring的程式碼到現在,一直都很習慣性的拷貝web.xml中的內容,沒怎麼在意裡面的內容,最近認真研究了下,很多東西都不是很理解,特別是classpath和classpath*的區別,研究了許久才搞明白,記錄下備忘。 classpath 和 classpath* 區別: classpath:只會到你