Ich kann die folgenden Beispiele nicht verstehen. Müssen wir etwas im XML tun, damit es funktioniert?
BEISPIEL 1
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
BEISPIEL 2
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
Wie können die beiden Klassen automatisch verdrahtet werden, indem sie dieselbe Schnittstelle implementieren und dieselbe Klasse verwenden?
Beispiel:
class Red implements Color
class Blue implements Color
class myMainClass{
@Autowired
private Color color;
draw(){
color.design();
}
}
Welche Entwurfsmethode wird aufgerufen? Wie stelle ich sicher, dass die Entwurfsmethode der Red-Klasse aufgerufen wird und nicht Blue?
Avi
TL;DR
Die @Autowired Annotation erspart Ihnen die Notwendigkeit, die Verdrahtung in der XML-Datei (oder auf andere Weise) selbst vorzunehmen, und findet für Sie einfach, was wo injiziert werden muss, und erledigt dies für Sie.
Vollständige Erklärung
Die @Autowired Annotation ermöglicht es Ihnen, Konfigurationen an anderer Stelle zu überspringen, was injiziert werden soll, und erledigt dies einfach für Sie. Angenommen, Ihr Paket ist com.mycompany.movies Sie müssen dieses Tag in Ihr XML (Anwendungskontextdatei) einfügen:
Dieses Tag führt einen automatischen Scan durch. Angenommen, jede Klasse, die zu einer Bean werden soll, wird mit einer korrekten Annotation wie annotiert @Component (für einfache Bohne) oder @Controller (für ein Servlet-Steuerelement) oder @Repository (zum DAO Klassen) und diese Klassen befinden sich irgendwo unter dem Paket com.mycompany.movies, Spring wird all diese finden und für jeden eine Bohne erstellen. Dies geschieht in 2 Scans der Klassen – beim ersten Mal sucht es nur nach Klassen, die zu einer Bohne werden müssen, und ordnet die Injektionen zu, die es tun muss, und beim zweiten Scan injiziert es die Bohnen. Natürlich können Sie Ihre Beans in der traditionelleren XML-Datei oder mit einer definieren @Configuration Klasse (oder eine beliebige Kombination der drei).
Die @Autowired Annotation teilt Spring mit, wo eine Injektion erfolgen muss. Wenn Sie es auf eine Methode setzen setMovieFinder es versteht (durch das Präfix set + die @Autowired Anmerkung), dass eine Bohne injiziert werden muss. Beim zweiten Scan sucht Spring nach einem Bean-Typ MovieFinder, und wenn es eine solche Bohne findet, injiziert es sie in diese Methode. Wenn es zwei solche Bohnen findet, erhalten Sie eine Exception. Um das zu vermeiden Exceptiondu kannst den … benutzen @Qualifier Anmerkung und teilen Sie ihm auf folgende Weise mit, welche der beiden Bohnen injiziert werden soll:
@Qualifier("redBean")
class Red implements Color {
// Class code here
}
@Qualifier("blueBean")
class Blue implements Color {
// Class code here
}
Oder wenn Sie es vorziehen, die Beans in Ihrem XML zu deklarieren, würde es ungefähr so aussehen:
Wenn Sie nicht zwei Anmerkungen verwenden möchten (die @Autowired und @Qualifier) können Sie verwenden @Resource um diese beiden zu kombinieren:
@Resource(name="redBean")
public void setColor(Color color) {
this.color = color;
}
Die @Resource (Sie können einige zusätzliche Daten dazu im ersten Kommentar zu dieser Antwort lesen) erspart Ihnen die Verwendung von zwei Anmerkungen und verwendet stattdessen nur eine.
Ich füge nur zwei weitere Kommentare hinzu:
Eine gute Praxis wäre zu verwenden @Inject anstatt @Autowired weil es nicht Spring-spezifisch ist und ist Teil von JSR-330 Standard.
Eine weitere gute Praxis wäre, die zu setzen @Inject / @Autowired auf einen Konstruktor statt auf eine Methode. Wenn Sie es auf einen Konstruktor setzen, können Sie überprüfen, ob die injizierten Beans nicht null sind und schnell fehlschlagen, wenn Sie versuchen, die Anwendung zu starten, und a vermeiden NullPointerException wenn Sie die Bohne tatsächlich verwenden müssen.
Aktualisieren: Um das Bild zu vervollständigen, habe ich eine neue Frage dazu erstellt @Configuration Klasse.
Nur um Ihre großartige Antwort zu vervollständigen: ‘@Resource’ ist Teil des JSR-250-Standards und hat eine zusätzliche Semantik über die einfache Injektion hinaus (Wie Sie gesagt haben, stammt ‘@Autowired’ von Spring; und ‘@Inject’ ist Teil von JSR-330) 🙂
– Ignacio Rubio
1. September 2014 um 15:12 Uhr
Wenn MovieFinder ist eine Schnittstelle, und wir haben eine Bohne für MovieFinderImpl(bean id = movieFinder), Spring wird es automatisch nach Typ oder Name einfügen?
– JaskeyLam
8. August 2015 um 12:37 Uhr
@jaskey – es hängt davon ab, ob Sie verwenden @Qualifier. Wenn ja – nach Namen, wenn nicht – nach Typ. By-type würde nur funktionieren, wenn Sie nur eine Bean vom Typ haben MovieFinder in deinem Kontext. Mehr als 1 würde zu einer Ausnahme führen.
– Avi
8. August 2015 um 17:07 Uhr
@Avi, tolle Antwort. Aber ich verstehe nicht, wie das @Autowired Anmerkung funktioniert auf der prepare Methode ein Beispiel 2. Es initialisiert die MovieRecommender aber technisch gesehen ist es so NICHT ein Setzer.
– Karan Chadha
28. Februar 2017 um 9:26 Uhr
@KaranChadha – Das @Autowired funktioniert auch für Konstrukteure. Es findet die erforderlichen Abhängigkeiten und injiziert sie in den Konstruktor.
– Avi
28. Februar 2017 um 9:59 Uhr
Aaron Digulla
Nichts im Beispiel besagt, dass die “Klassen dieselbe Schnittstelle implementieren”. MovieCatalog ist ein Typ und CustomerPreferenceDao ist ein anderer Typ. Der Frühling kann sie leicht voneinander unterscheiden.
In Spring 2.x erfolgte die Verknüpfung von Beans meist über Bean-IDs oder -Namen. Dies wird immer noch von Spring 3.x unterstützt, aber oft haben Sie eine Instanz einer Bean mit einem bestimmten Typ – die meisten Dienste sind Singletons. Das Erstellen von Namen für diese ist mühsam. Also begann Spring, “autowire by type” zu unterstützen.
Was die Beispiele zeigen, sind verschiedene Möglichkeiten, wie Sie Beans in Felder, Methoden und Konstruktoren einfügen können.
Das XML enthält bereits alle Informationen, die Spring benötigt, da Sie in jeder Bean den vollqualifizierten Klassennamen angeben müssen. Bei Schnittstellen muss man allerdings etwas aufpassen:
Da Java die Parameternamen nicht im Bytecode hält, kann Spring nicht mehr zwischen den beiden Beans unterscheiden. Die Lösung ist zu verwenden @Qualifier:
@AaronDigulla Das war schön. Ich möchte jedoch wissen, wie Sie die Funktion aufrufen preparewelche Parameter werden verwendet, um diese Funktion aufzurufen?
– Nguyen Quang Anh
10. Juli 2017 um 2:04 Uhr
@NguyenQuangAnh Ich rufe die Methode nicht auf, Spring wird es tun, wenn die Bean erstellt wird. Das passiert genau wann @Autowired Felder injiziert werden. Spring erkennt dann, dass Parameter benötigt werden, und verwendet dieselben Regeln, die für die Feldinjektion verwendet werden, um die Parameter zu finden.
– Aaron Digulla
4. September 2017 um 11:53 Uhr
Ja, Sie können die Spring-Servlet-Kontext-XML-Datei konfigurieren, um Ihre Beans (dh Klassen) zu definieren, damit sie die automatische Injektion für Sie übernehmen kann. Beachten Sie jedoch, dass Sie andere Konfigurationen vornehmen müssen, um Spring zum Laufen zu bringen, und der beste Weg, dies zu tun, besteht darin, einem Tutorial von Grund auf zu folgen.
Sobald Sie Ihr Spring wahrscheinlich konfiguriert haben, können Sie Folgendes in Ihrer Spring-Servlet-Kontext-XML-Datei tun, damit Beispiel 1 oben funktioniert (bitte ersetzen der Paketname von com.filme wie der wahre Paketname lautet und wenn es sich um eine Klasse eines Drittanbieters handelt, stellen Sie sicher, dass sich die entsprechende JAR-Datei im Klassenpfad befindet):