<context:annotation-config>
wird verwendet, um Annotationen in Beans zu aktivieren, die bereits im Anwendungskontext registriert sind (unabhängig davon, ob sie mit XML oder durch Paket-Scanning definiert wurden).
<context:component-scan>
kann auch tun, was <context:annotation-config>
tut aber <context:component-scan>
durchsucht auch Pakete, um Beans im Anwendungskontext zu finden und zu registrieren.
Ich werde einige Beispiele anführen, um die Unterschiede/Ähnlichkeiten zu verdeutlichen.
Beginnen wir mit einem Grundaufbau von drei Bohnen des Typs A
, B
y C
, mit B
y C
wird injiziert in 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;
}
}
Mit der folgenden XML-Konfiguration :
<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>
Das Laden des Kontexts führt zu folgender Ausgabe:
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, das ist die erwartete Ausgabe. Aber das ist Spring im "alten Stil". Jetzt haben wir Anmerkungen, also verwenden wir diese, um die XML zu vereinfachen.
Zunächst wird die bbb
y ccc
Eigenschaften der Bohne A
etwa so:
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;
}
}
Dadurch kann ich die folgenden Zeilen aus der XML-Datei entfernen:
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
Mein XML ist nun auf diese Weise vereinfacht:
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
Wenn ich den Kontext lade, erhalte ich die folgende Ausgabe:
creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf
OK, das ist falsch! Was ist passiert? Warum sind meine Eigenschaften nicht automatisch verdrahtet?
Nun, Anmerkungen sind eine nette Funktion, aber für sich genommen bringen sie gar nichts. Sie kommentieren nur etwas. Man braucht ein Verarbeitungswerkzeug, um die Anmerkungen zu finden und etwas mit ihnen anzufangen.
<context:annotation-config>
zur Rettung. Es aktiviert die Aktionen für die Anmerkungen, die es auf den Beans findet, die im gleichen Anwendungskontext definiert sind, in dem es selbst definiert ist.
Wenn ich mein XML wie folgt ändere:
<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
wenn ich den Anwendungskontext lade, erhalte ich das richtige Ergebnis:
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, das ist schön, aber ich habe zwei Zeilen aus der XML-Datei entfernt und eine hinzugefügt. Das ist kein sehr großer Unterschied. Die Idee mit den Anmerkungen ist, dass sie das XML entfernen sollen.
Entfernen wir also die XML-Definitionen und ersetzen sie alle durch Anmerkungen:
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;
}
}
Während wir in der XML nur diese behalten:
<context:annotation-config />
Wir laden den Kontext und das Ergebnis ist... nichts. Keine Beans werden erstellt, keine Beans werden autowired. Nichts!
Das liegt daran, dass, wie ich im ersten Absatz sagte, die <context:annotation-config />
funktioniert nur bei Beans, die im Anwendungskontext registriert sind. Da ich die XML-Konfiguration für die drei Beans entfernt habe, wird keine Bean erstellt und <context:annotation-config />
hat keine "Ziele", an denen er arbeiten kann.
Aber das wird kein Problem sein für <context:component-scan>
die ein Paket nach "Zielen" durchsuchen kann, die bearbeitet werden sollen. Ändern wir den Inhalt der XML-Konfiguration in den folgenden Eintrag:
<context:component-scan base-package="com.xxx" />
Wenn ich den Kontext lade, erhalte ich die folgende Ausgabe:
creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff
Hmmmm... irgendetwas fehlt. Und warum?
Wenn Sie sich die Klassen genau ansehen, ist die Klasse A
hat Paket com.yyy
aber ich habe in der <context:component-scan>
Paket zu verwenden com.xxx
Das ging also völlig an mir vorbei. A
Klasse und nahm nur B
y C
die sich auf der com.xxx
Paket.
Um dies zu beheben, füge ich auch dieses andere Paket hinzu:
<context:component-scan base-package="com.xxx,com.yyy" />
und jetzt erhalten wir das erwartete Ergebnis:
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
Und das war's! Jetzt haben Sie keine XML-Definitionen mehr, sondern Anmerkungen.
Ein letztes Beispiel für die Beibehaltung der annotierten Klassen A
, B
y C
und dem XML folgendes hinzufügen, was erhalten wir nach dem Laden des Kontexts?
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
Wir erhalten trotzdem das richtige Ergebnis:
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
Auch wenn die Bohne für die Klasse A
nicht durch Scannen erhalten wird, werden die Verarbeitungswerkzeuge weiterhin durch <context:component-scan>
für alle registrierten Bohnen im Anwendungskontext, auch für A
die manuell in die XML-Datei eingetragen wurde.
Aber was, wenn wir die folgende XML haben, werden wir doppelte Bohnen erhalten, weil wir beide angegeben haben <context:annotation-config />
y <context:component-scan>
?
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
Nein, keine Überschneidungen, wir erhalten wieder das erwartete Ergebnis:
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
Das liegt daran, dass beide Tags die gleichen Verarbeitungswerkzeuge registrieren ( <context:annotation-config />
kann weggelassen werden, wenn <context:component-scan>
angegeben ist), aber Spring kümmert sich darum, dass sie nur einmal ausgeführt werden.
Auch wenn Sie die Verarbeitungswerkzeuge selbst mehrfach registrieren, sorgt Spring dafür, dass sie ihre Arbeit nur einmal verrichten; diese 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" />
wird immer noch das folgende Ergebnis liefern:
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, das war's dann wohl.
Ich hoffe, diese Informationen sowie die Antworten von @Tomasz Nurkiewicz und @Sean Patrick Floyd reichen aus, um zu verstehen, wie <context:annotation-config>
y <context:component-scan>
Arbeit.