Pytanie Jaki jest priorytet definicji ziaren Springa?


Kiedy kilka fasoli Spring jest zdefiniowanych o tej samej nazwie, które ukryje pozostałe?

Załóżmy, że mam kilka zajęć z przypisami @Component("bean") w pakiecie org.example plus plik applicationContext.xml zawierający:

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

Komórki zostaną pobrane, gdy zrobię applicationContext.getBean("bean")?

Według Dokumentacja wiosna:

Każdy komponent bean ma jeden lub więcej identyfikatorów. Te identyfikatory muszą być unikalne w kontenerze obsługującym komponent bean.

Wiem jednak (ponieważ testowałem), że Spring nie będzie narzekać, kiedy to się stanie. Jedna definicja ukryje pozostałe. Ale nie mogłem dowiedzieć się, jaka była zasada.

Chcę to zrobić w celu testowania. Używam konfiguracji opartej na adnotacjach w celu zdefiniowania prawdziwych (produkcyjnych) komponentów. Następnie chcę użyć pliku konfiguracyjnego XML specyficznego dla testu, aby zastąpić te definicje i wstrzyknąć fascynację próbną.

Edycja: Ponieważ miałeś kilka zapytań o logi, poświęciłem trochę czasu na tworzenie. Oto one:

  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

Po kilku testach odkryłem, że otrzymuję wyjątek podczas tworzenia kontekstu, jeśli:

  • mam dwa @Component("bean")  lub
  • mam dwa <bean id="bean"/> elementy w podobnie Plik XML.

21
2018-03-05 20:45


pochodzenie


Jeśli używasz konfiguracji specyficznej dla testu, jakie inne komponenty mogą zastąpić? - Sotirios Delimanolis
Skonfigurowane komponenty bean oparte na adnotacjach. Mój plik konfiguracyjny testu zawiera element <context: component-scan />, ponieważ większość komponentów to te prawdziwe. Tylko kilka trzeba zmienić. - Etienne Miret
Czy rejestr startowy pokazuje cokolwiek? Ponieważ, jak powiedziałeś, wiosna może mieć tylko jeden komponent dla każdego identyfikatora. Zależy od tego, co ładuje najpierw, klasy z adnotacjami lub xml. - Sotirios Delimanolis
Rozumiem, że musisz to zrobić, ale nadal nie jest to dobrą praktyką. Wierzę, że Spring będzie generować błędy podczas tworzenia więcej niż jednego komponentu o tym samym "id" - NIE IMIĘ. Powinieneś po prostu użyć EasyMock do wyśmiewania i wstrzykiwania fasoli, a nie innego pliku konfiguracyjnego. easymock.org/EasyMock3_1_Documentation.html - ninnemannk
Poza powyższym zaleceniem - co mówią twoje logi startowe? Powinni wypisać nazwę każdego komponentu, który tworzą. - ninnemannk


Odpowiedzi:


  • Fasola jest zarejestrowana w kolejności, która znajduje się w pliku definicji xml.

  • Zeskanowane ziarna są rejestrowane w punkcie, w którym znaleziono znacznik xml, ale zeskanowane ziarna nie mogą zastąpić wcześniej zarejestrowanych definicji fasoli.

  • Definicje ziarna Xml mogą zastąpić dowolną wcześniejszą definicję komponentu bean, jeśli DefaultListableBeanFactory.allowBeanDefinitionOverriding jest prawdziwe (domyślnie).

Więc XML wygrywa.

Jeśli najpierw umieścisz znacznik skanowania komponentu, komponenty xml przesłonią zeskanowane. Jeśli umieścisz go jako ostatni, zeskanowane ziarna zostaną zignorowane.

Edytować 

Aliasy mają różne zachowania, jeśli zostały zadeklarowane w atrybucie nazwy w definicji komponentu bean lub zadeklarowane za pomocą znacznika aliasu.

  • aliasy zadeklarowane za pomocą znacznika aliasu ukrywają późniejszą definicję komponentu bean o tej samej nazwie.
  • aliasy zadeklarowane w atrybucie name zapobiegają używaniu przez dowolną inną definicję komponentu bean tej samej nazwy przez wyrzucenie a BeanDefinitionParsingException.

Na przykład:

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

ale

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

Różnica polega na tym BeanDefinitionParserDelegate trzymaj listę używanych nazw i aliasów na tym samym poziomie komponentu bean, w którym znajduje się element bean, i sprawdź unikalność nazwy podczas analizowania definicji komponentów bean.

Tag aliasu jest przetwarzany bezpośrednio przez DefaultBeanDefinitionDocumentReader.processAliasRegistration() a delegat parsera nie jest świadomy tych nazw.

Nie wiem, czy to błąd, czy celowo, ale odniesienie  nie mówi nic i wydaje się, że oczekuje się, że wewnętrzne i zewnętrzne deklaracje aliasów będą miały takie samo zachowanie.


27
2018-03-05 23:49



Właściwie to zauważyłem <alias> zastępuje dowolną późniejszą definicję komponentu bean. Ale masz rację, że zeskanowana fasola nie może zastąpić zeskanowanego xml, bez względu na to, gdzie umieściłem element skanowania podzespołów. - Etienne Miret
Tak, przetestowałem to. Alias ​​powoduje, że definicja komponentu bean o tej samej nazwie jest niedostępna. Definicję komponentu bean można nadal pobrać za pomocą metody factoryBean.getBeanDefinition (), ale fabryka nie będzie jej tworzyć, a komponent bean nie będzie kandydatem do automatycznego wyprowadzania przez typ lub pobrany przez factory.getBean (type) - Jose Luis Martin
@JoseLuisMartin Rozumiem, że XML wygrywa, ale co jeśli AnnotationConfigApplicationContext skanuje dwie fasole o tej samej nazwie. W jaki sposób decyduje, która definicja fasoli nadaje priorytet - Edge