Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the precedence of Spring beans definitions?

Tags:

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.
like image 450
Étienne Miret Avatar asked Mar 05 '13 20:03

Étienne Miret


People also ask

In what order does Spring create beans?

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.

How is the bean defined in Spring?

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.

What is Spring Main allow bean definition overriding?

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.


1 Answers

  • 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.

like image 137
Jose Luis Martin Avatar answered Oct 06 '22 15:10

Jose Luis Martin