Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

When several Spring beans are defined with the same name, which one will hide the others?

Let's say I have several classes annotated with @Component("bean") in the package org.example, plus an applicationContext.xml that contains:

<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"/>

Which bean will be retrieved when I do an applicationContext.getBean("bean")?

According to the Spring documentation:

Every bean has one or more identifiers. These identifiers must be unique within the container that hosts the bean.

However, I know (because I tested) that Spring won't complain when this is done. One definition will hide the others. But I couldn't find out what was the rule.

I want to do this for testing purpose. I use annotation based configuration in order to define real (production) beans. Then I want to use a test-specific XML configuration file to override these definitions and inject mock beans.

Edit: Since you were several to ask for logs, I spent some time creating some. Here are they:

  0 INFO  org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@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.springframework.beans.factory.support.DefaultListableBeanFactory@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.springframework.context.support.ClassPathXmlApplicationContext@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.springframework.beans.factory.support.DefaultListableBeanFactory@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

After some tests, I found out that I get an exception during context creation if:

  • I have two @Component("bean") or
  • I have two <bean id="bean"/> elements in the same XML file.
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
125 views
Welcome To Ask or Share your Answers For Others

1 Answer

  • Beans are registered in the order that are found in xml definition file.

  • Scanned beans are registered at point that the xml tag is found but scanned beans cannot override previously registered bean definitions.

  • Xml beans definitions can override any previously bean definition if DefaultListableBeanFactory.allowBeanDefinitionOverriding is true (by default).

So XML Wins.

If you put the component-scan tag first, xml beans will override scanned ones. If you put it last, scanned beans will be ignored.

Edit

Aliases have diferent behavior if declared in name attribute in a bean definition or declared using the alias tag.

  • aliases declared with the alias tag hides any later bean definition with the same name.
  • aliases declared in name attribute prevent any other bean definition to use the same name by throwing a BeanDefinitionParsingException.

For example:

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

but

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

The diference is that BeanDefinitionParserDelegate hold a list of names and aliases in use at the same bean level of beans element nesting and check for name uniqueness when parsing bean definitions.

The alias tag is processed directly by DefaultBeanDefinitionDocumentReader.processAliasRegistration() and the parser delegate is unaware of this names.

I don't know if it's a bug or intentional but reference does not say anything about and seem to be expected that the internal and external declarations of aliases have the same behavior.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...