Подтвердить что ты не робот

Каков приоритет определения Spring beans?

Когда несколько Spring beans определены с тем же именем, какое из них будет скрыто?

Предположим, что у меня есть несколько классов, аннотированных с помощью @Component("bean") в пакете org.example, плюс applicationContext.xml, который содержит:

<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 будет получен, когда я сделаю applicationContext.getBean("bean")?

В соответствии с Spring документацией:

Каждый bean имеет один или несколько идентификаторов. Эти идентификаторы должны быть уникальными в контейнере, в котором размещается bean.

Однако, я знаю (потому что я тестировал), что Spring не будет жаловаться, когда это будет сделано. Одно определение скроет остальных. Но я не мог узнать, что было правилом.

Я хочу сделать это для тестирования. Я использую конфигурацию на основе аннотации, чтобы определить реальную (производственную) beans. Затем я хочу использовать тестовый файл конфигурации XML, чтобы переопределить эти определения и ввести mock beans.

Изменить. Поскольку вам было несколько, чтобы просить журналы, я потратил некоторое время на создание некоторых. Вот они:

  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.
4b9b3361

Ответ 1

  • Beans регистрируются в порядке, указанном в файле определения xml.

  • Отсканированные beans регистрируются в точке, где найден тэг xml, но сканированный beans не может переопределять ранее зарегистрированные определения bean.

  • Определения Xml beans могут переопределять любое ранее определение bean, если DefaultListableBeanFactory.allowBeanDefinitionOverriding истинно (по умолчанию).

Итак, побеждает XML.

Если вы сначала поместите тег компонентного сканирования, xml beans переопределит сканированные. Если вы поместите его последним, отсканированный beans будет проигнорирован.

Изменить

Псевдонимы имеют различное поведение, если объявлено в атрибуте имени в определении bean или объявлены с использованием тега псевдонима.

  • псевдонимы, объявленные с тегом alias, скрывают любое последующее определение bean с тем же именем.
  • псевдонимы, объявленные в атрибуте name, не позволяют любому другому определению bean использовать одно и то же имя, выбрасывая BeanDefinitionParsingException.

Например:

 <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 вложенности элементов beans, и проверяет уникальность имени при анализе определений bean.

Тег псевдонима обрабатывается непосредственно DefaultBeanDefinitionDocumentReader.processAliasRegistration(), и делегат-парсер не знает об этих именах.

Я не знаю, является ли это ошибкой или преднамеренным, но reference ничего не говорит и, похоже, ожидается, что внутренняя и внешние декларации псевдонимов имеют одинаковое поведение.