724 Stimmen

Unterschied zwischen <context:annotation-config> und <context:component-scan>

Ich lerne gerade Spring 3 und scheine die Funktionalität dahinter nicht zu verstehen <context:annotation-config> y <context:component-scan> .

Nach dem, was ich gelesen habe, scheinen sie unterschiedlich zu handeln Anmerkungen ( @Required , @Autowired usw. gegen @Component , @Repository , @Service usw.), aber auch von dem, was ich gelesen habe, registrieren sie die gleichen Bohnen-Postprozessor Klassen.

Um mich noch mehr zu verwirren, gibt es eine annotation-config Attribut auf <context:component-scan> .

Kann jemand etwas Licht auf diese Tags werfen? Was ist ähnlich, was ist anders, wird das eine durch das andere ersetzt, ergänzen sie sich gegenseitig, brauche ich eines davon, beide?

1485voto

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

170voto

Tomasz Nurkiewicz Punkte 322861

Ich fand diese schöne Zusammenfassung welche Vermerke von welchen Erklärungen übernommen werden. Wenn Sie es studieren, werden Sie feststellen, dass <context:component-scan/> erkennt eine Obermenge von Anmerkungen, die von <context:annotation-config/> , nämlich:

  • @Component , @Service , @Repository , @Controller , @Endpoint
  • @Configuration , @Bean , @Lazy , @Scope , @Order , @Primary , @Profile , @DependsOn , @Import , @ImportResource

Wie Sie sehen können <context:component-scan/> logischerweise erweitert <context:annotation-config/> mit CLASSPATH-Komponentensuche und Java @Configuration-Funktionen.

99voto

user2673474 Punkte 1041

Mit Spring können Sie zwei Dinge tun:

  1. Selbstverdrahtung von Bohnen
  2. Autodiscovery von Bohnen

1. Selbstverdrahtung
Normalerweise in applicationContext.xml Sie definieren Beans und andere Beans werden verdrahtet mit Konstruktor- oder Setter-Methoden. Sie können Beans mithilfe von XML oder Annotationen verdrahten. Wenn Sie Annotationen verwenden, müssen Sie diese aktivieren, und Sie müssen <context:annotation-config /> in applicationContext.xml . Dies vereinfacht die Struktur des Tags von applicationContext.xml weil Sie die Beans nicht manuell verdrahten müssen (Konstruktor oder Setter). Sie können verwenden @Autowire Annotation und die Beans werden nach Typ verdrahtet.

Ein Schritt nach vorn, um die manuelle XML-Konfiguration zu umgehen, ist

2. Autodiscovery
Autodiscovery vereinfacht die XML einen Schritt weiter, da man nicht einmal mehr die <bean> Tag einfügen applicationContext.xml . Sie markieren einfach die spezifischen Beans mit einer der folgenden Annotationen und Spring wird die markierten Beans und ihre Abhängigkeiten automatisch in den Spring-Container einbinden. Die Annotationen sind wie folgt: @Controller , @Service , @Komponente , @Repository . Durch die Verwendung <context:component-scan> und auf das Basispaket zeigen, wird Spring die Komponenten automatisch erkennen und in den Spring-Container einbinden.


Als Schlussfolgerung:

  • <context:annotation-config /> wird verwendet, um die Möglichkeit zu haben @Autowired Anmerkung
  • <context:component-scan /> wird verwendet, um die Suche von bestimmten Bohnen und dem Versuch der Selbstverdrahtung.

39voto

Sean Patrick Floyd Punkte 283617

<context:annotation-config> aktiviert viele verschiedene Annotationen in Beans, unabhängig davon, ob sie in XML oder durch Komponenten-Scanning definiert sind.

<context:component-scan> dient der Definition von Beans ohne Verwendung von XML

Für weitere Informationen lesen Sie bitte:

34voto

Premraj Punkte 65511

<context:annotation-config> : Scannen und Aktivieren von Annotationen für bereits registrierte Beans in spring config xml.

<context:component-scan> : Anmeldung Bohne + <context:annotation-config>


@Autowired und @Required sind Ziele auf Eigentumsebene daher sollte sich die Bohne vor der Verwendung dieser Anmerkungen im Spring IOC registrieren. Um diese Annotationen zu aktivieren, müssen entweder die entsprechenden Beans registriert oder <context:annotation-config /> . d.h. <context:annotation-config /> funktioniert nur mit registrierten Bohnen.

@Erforderlich ermöglicht RequiredAnnotationBeanPostProcessor Bearbeitungswerkzeug
@Autowired ermöglicht AutowiredAnnotationBeanPostProcessor Bearbeitungswerkzeug

Anmerkung: Annotation selbst nichts zu tun, wir brauchen eine Verarbeitungswerkzeug die eine darunter liegende Klasse ist, die für den Kernprozess verantwortlich ist.


@Repository, @Service und @Controller sind @Component und sie Ziele der Klassenstufe .

<context:component-scan> Es scannt das Paket und findet und registriert die Bohnen, und es schließt die Arbeit ein, die von <context:annotation-config /> .

Migrieren von XML zu Annotationen

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X