<context:annotation-config>
służy do aktywacji adnotacji w komponentach bean już zarejestrowanych w kontekście aplikacji (bez względu na to, czy zostały one zdefiniowane za pomocą XML, czy poprzez skanowanie pakietów).
<context:component-scan>
może również robić to, co <context:annotation-config>
robi, ale<context:component-scan>
także skanuje pakiety, aby znaleźć i zarejestrować komponenty bean w kontekście aplikacji.
Wykorzystam kilka przykładów, aby pokazać różnice / podobieństwa.
Zacznijmy od podstawowej konfiguracji trzech ziaren tego typu A
, B
i C
, B
i C
wstrzyknięcia do A
.
package com.xxx;
public class B {
public B() {
System.out.println("creating bean B: " + this);
}
}
package com.xxx;
public class C {
public C() {
System.out.println("creating bean C: " + this);
}
}
package com.yyy;
import com.xxx.B;
import com.xxx.C;
public class A {
private B bbb;
private C ccc;
public A() {
System.out.println("creating bean A: " + this);
}
public void setBbb(B bbb) {
System.out.println("setting A.bbb with " + bbb);
this.bbb = bbb;
}
public void setCcc(C ccc) {
System.out.println("setting A.ccc with " + ccc);
this.ccc = ccc;
}
}
Dzięki następującej konfiguracji XML:
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A">
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
</bean>
Ładowanie kontekstu daje następujące wyniki:
creating bean B: com.xxx.B@c2ff5
creating bean C: com.xxx.C@1e8a1f6
creating bean A: com.yyy.A@1e152c5
setting A.bbb with com.xxx.B@c2ff5
setting A.ccc with com.xxx.C@1e8a1f6
OK, to oczekiwany wynik. Ale to wiosna w „starym stylu”. Teraz mamy adnotacje, więc wykorzystajmy je, aby uprościć XML.
Po pierwsze, pozwala na automatyczne bbb
i ccc
właściwości bean w następujący A
sposób:
package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import com.xxx.B;
import com.xxx.C;
public class A {
private B bbb;
private C ccc;
public A() {
System.out.println("creating bean A: " + this);
}
@Autowired
public void setBbb(B bbb) {
System.out.println("setting A.bbb with " + bbb);
this.bbb = bbb;
}
@Autowired
public void setCcc(C ccc) {
System.out.println("setting A.ccc with " + ccc);
this.ccc = ccc;
}
}
To pozwala mi usunąć następujące wiersze z pliku XML:
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
Mój XML jest teraz uproszczony do tego:
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
Podczas ładowania kontekstu otrzymuję następujące dane wyjściowe:
creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf
OK, to źle! Co się stało? Dlaczego moje właściwości nie są tworzone automatycznie?
Cóż, adnotacje są fajną funkcją, ale same w sobie nic nie robią. Po prostu dodają adnotacje. Potrzebujesz narzędzia do przetwarzania, aby znaleźć adnotacje i coś z nimi zrobić.
<context:annotation-config>
na pomoc. To aktywuje akcje dla adnotacji, które znajdzie na komponentach bean zdefiniowanych w tym samym kontekście aplikacji, w którym sama jest zdefiniowana.
Jeśli zmienię XML na to:
<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
po załadowaniu kontekstu aplikacji uzyskuję odpowiedni wynik:
creating bean B: com.xxx.B@15663a2
creating bean C: com.xxx.C@cd5f8b
creating bean A: com.yyy.A@157aa53
setting A.bbb with com.xxx.B@15663a2
setting A.ccc with com.xxx.C@cd5f8b
OK, to miłe, ale usunąłem dwa wiersze z pliku XML i dodałem jeden. To nie jest bardzo duża różnica. Pomysł z adnotacjami polega na tym, że ma on usunąć XML.
Usuńmy więc definicje XML i zastąpmy je adnotacjami:
package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class B {
public B() {
System.out.println("creating bean B: " + this);
}
}
package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class C {
public C() {
System.out.println("creating bean C: " + this);
}
}
package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.xxx.B;
import com.xxx.C;
@Component
public class A {
private B bbb;
private C ccc;
public A() {
System.out.println("creating bean A: " + this);
}
@Autowired
public void setBbb(B bbb) {
System.out.println("setting A.bbb with " + bbb);
this.bbb = bbb;
}
@Autowired
public void setCcc(C ccc) {
System.out.println("setting A.ccc with " + ccc);
this.ccc = ccc;
}
}
Podczas gdy w XML zachowujemy tylko to:
<context:annotation-config />
Ładujemy kontekst, a wynik jest ... Nic. Żadne ziarna nie są tworzone, żadne ziarna nie są automatycznie przetwarzane. Nic!
Jest tak, ponieważ, jak powiedziałem w pierwszym akapicie, <context:annotation-config />
jedyne działa na fasolach zarejestrowanych w kontekście aplikacji. Ponieważ usunąłem konfigurację XML dla trzech ziaren, nie ma żadnego komponentu bean i <context:annotation-config />
nie ma „celów” do pracy.
Ale to nie będzie problem, w przypadku <context:component-scan>
którego można przeskanować pakiet w poszukiwaniu „celów”, nad którymi będzie działać. Zmieńmy zawartość konfiguracji XML na następujący wpis:
<context:component-scan base-package="com.xxx" />
Podczas ładowania kontekstu otrzymuję następujące dane wyjściowe:
creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff
Hmmmm ... czegoś brakuje. Dlaczego?
Jeśli przyjrzysz się bliżej klasom, klasa A
ma pakiet, com.yyy
ale określiłem go w <context:component-scan>
pakiecie do użycia, com.xxx
więc całkowicie pominąłem moją A
klasę i tylko odebrałem B
i C
którecom.xxx
pakiecie.
Aby to naprawić, dodaję również ten inny pakiet:
<context:component-scan base-package="com.xxx,com.yyy" />
a teraz otrzymujemy oczekiwany wynik:
creating bean B: com.xxx.B@cd5f8b
creating bean C: com.xxx.C@15ac3c9
creating bean A: com.yyy.A@ec4a87
setting A.bbb with com.xxx.B@cd5f8b
setting A.ccc with com.xxx.C@15ac3c9
I to wszystko! Teraz nie masz już definicji XML, masz adnotacje.
Jako ostatni przykład, zachowując adnotacjami klas A
, B
a C
i dodanie następujących do XML, co otrzymamy po załadowaniu kontekst?
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
Nadal otrzymujemy poprawny wynik:
creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87
Nawet jeśli fasola dla klasy A
nie zostanie uzyskana przez skanowanie, narzędzia przetwarzania są nadal stosowane do <context:component-scan>
wszystkich ziaren zarejestrowanych w kontekście aplikacji, nawet dlaA
których została ręcznie zarejestrowana w pliku XML.
Ale co, jeśli będziemy mieć następujący kod XML, czy otrzymamy zduplikowane komponenty bean, ponieważ wybraliśmy oba <context:annotation-config />
i <context:component-scan>
?
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
Nie, bez duplikatów, ponownie otrzymujemy oczekiwany wynik:
creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87
Jest tak, ponieważ oba tagi rejestrują te same narzędzia przetwarzania ( <context:annotation-config />
można je pominąć, jeśli <context:component-scan>
jest określony), ale Spring zadba o ich uruchomienie tylko raz.
Nawet jeśli zarejestrujesz narzędzia do przetwarzania wiele razy, Spring nadal upewni się, że wykonają swoją magię tylko raz; ten XML:
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
<bean id="bla" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla1" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla2" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla3" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
nadal będzie generować następujący wynik:
creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@25d2b2
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87
OK, chodzi o rapowanie.
Mam nadzieję, że te informacje wraz z odpowiedziami @Tomasz Nurkiewicz i @Sean Patrick Floyd są wszystkim, czego potrzebujesz, aby zrozumieć, jak <context:annotation-config>
i jak
<context:component-scan>
pracować.