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:
@Component("bean")
or <bean id="bean"/>
elements in the same XML file.Order of bean initialization should not matter since the fields are injected after creating the bean. The only problem where the order will matter is when the bean is needed at constructor argument of other class, but Spring notices this and will solve it.
In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application.
Main. Allow bean definition overriding = false, which will immediately provide you with information that you have beans with the same name and there are conflicts between them. If this code is yours, and you can change the name of the Bean in any way - just do this and inject the required code.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With