2013-03-05 96 views
21

當幾個Spring bean被定義爲相同的名稱時,哪一個會隱藏其他bean?Spring bean定義的優先級是什麼?

比方說,我已經標註了在包org.example @Component("bean")幾類,以及包含一個applicationContext.xml中:當我做一個applicationContext.getBean("bean")

<context:component-scan base-package="org.example"/> 
<alias name="aliasedBean" alias="bean"/> 
<bean id="aliasedBean" class="org.example.AliasedBean"/> 
<bean id="bean" class="org.example.XmlBean"/> 
<import resource="otherApplicationContext.xml"/> 

至極bean將被檢索?

按照Spring documentation

每個bean都有一個或多個標識符。這些標識符在託管bean的容器內必須是唯一的。

但是,我知道(因爲我測試過),Spring完成後不會抱怨。一個定義會隱藏其他定義。但我找不到什麼是規則。

我想做這個測試目的。我使用基於註釋的配置來定義真實(生產)bean。然後我想使用特定於測試的XML配置文件來覆蓋這些定義並注入模擬bean。

編輯:由於你是幾個要求日誌,我花了一些時間創造一些。這裏是他們:

0 INFO org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org[email protected]3934f69a: startup date [Wed Mar 06 23:04:35 CET 2013]; root of context hierarchy 
45 INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [applicationContext.xml] 
223 INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Overriding bean definition for bean 'bean': replacing [Generic bean: class [org.example.AnnotatedBean]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [/Users/etienne/Documents/Développement/Registre/workspace/SpringPrecedence/target/classes/org/example/AnnotatedBean.class]] with [Generic bean: class [org.example.XmlBean]; scope=; 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 [applicationContext.xml]] 
223 INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [otherApplicationContext.xml] 
246 INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Overriding bean definition for bean 'bean': replacing [Generic bean: class [org.example.XmlBean]; scope=; 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 [applicationContext.xml]] with [Generic bean: class [org.example.ImportedXmlBean]; scope=; 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 [otherApplicationContext.xml]] 
290 INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.s[email protected]6aba4211: defining beans [bean,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,aliasedBean,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy 
290 INFO org.example.AliasedBean - Construction of AliasedBean. 
302 INFO org.example.Main - Application context loaded. 
302 INFO org.springframework.context.support.ClassPathXmlApplicationContext - Closing org[email protected]3934f69a: startup date [Wed Mar 06 23:04:35 CET 2013]; root of context hierarchy 
302 INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.s[email protected]6aba4211: defining beans [bean,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,aliasedBean,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy 

一些測試後,我發現我的上下文創建過程中得到一個例外,如果:

  • 我有兩個@Component("bean")
  • 我有兩個<bean id="bean"/>元素相同 XML文件。
+0

如果您使用的是特定於測試的配置,那麼還有哪些其他bean可以覆蓋? – 2013-03-05 20:49:13

+0

基於註釋的配置bean。我的測試配置文件包含,因爲大多數bean都是真正的。只有少數需要被覆蓋。 – 2013-03-05 21:06:01

+0

啓動日誌是否顯示任何內容?正如你所說,春天每個id只能有一個bean。這取決於它首先加載什麼,註釋類或xml。 – 2013-03-05 21:12:15

回答

27
  • 豆類登記在了在XML定義文件中找到的順序。

  • 掃描的bean是在找到xml標記的位置註冊的,但掃描的bean不能覆蓋以前註冊的bean定義。

  • 如果DefaultListableBeanFactory.allowBeanDefinitionOverriding爲true(默認情況下),則Xml bean定義可以覆蓋以前的任何bean定義。

So XML Wins。

如果您先將組件掃描標籤放入,則xml bean將覆蓋掃描標籤。如果你把它放在最後,被掃描的bean將被忽略。

編輯

別名有diferent的行爲,如果在一個bean定義名稱屬性聲明或使用別名標籤聲明。

  • 使用別名標籤聲明的別名隱藏了任何後來的具有相同名稱的bean定義。
  • 在name屬性中聲明的別名會通過拋出BeanDefinitionParsingException阻止任何其他bean定義使用相同的名稱。

例如:

<bean id="foo" name="bar" class="Foo" /> 
<bean id="bar" class="Bar" /> -- throw Exception (name bar is in use) 

<bean id="foo" class="Foo" /> 
<alias name="foo" alias="bar" /> 
<bean id="bar" class="Bar" /> -- Hidden by alias no exception thrown 

的性差異是BeanDefinitionParserDelegate在豆類元素嵌套的同一個bean水平保持在使用的名稱和別名的列表,並檢查解析bean定義時的名稱唯一性。

別名標記直接由DefaultBeanDefinitionDocumentReader.processAliasRegistration()處理,解析器委託不知道這個名稱。

我不知道它是一個錯誤還是故意的,但reference沒有提到任何內容,並且似乎預計別名的內部和外部聲明具有相同的行爲。

+0

實際上,我發現''覆蓋了後面的任何bean定義。但是,無論在哪裏放置組件掃描元素,掃描的bean都無法覆蓋xml,這是正確的。 – 2013-03-06 22:26:32

+0

是的,我測試過它。一個別名使bean定義具有相同的名稱不可見。這個bean的定義仍然可以通過factoryBean.getBeanDefinition()來獲取,但是工廠不會實例化它,並且這個bean不會被按類型自動裝配,或者被factory.getBean(類型)檢索到。 – 2013-03-07 10:22:16

+1

@JoseLuisMartin我明白XML贏了,但是如果AnnotationConfigApplicationContext掃描兩個具有相同名稱的bean,該怎麼辦?它如何決定哪個bean定義優先 – Edge 2014-01-15 13:23:57