JavaRush /Java-Blog /Random-DE /Der Frühling ist etwas für Faule. Grundlagen, Grundkonzep...
Стас Пасинков
Level 26
Киев

Der Frühling ist etwas für Faule. Grundlagen, Grundkonzepte und Beispiele mit Code. Teil 2

Veröffentlicht in der Gruppe Random-DE
Im letzten Artikel habe ich kurz und bündig erklärt, was Frühling ist, was Behälter sind und welchen Kontext sie haben. Jetzt ist es an der Zeit, auszuprobieren, wie das alles funktioniert. Der Frühling ist etwas für Faule.  Grundlagen, Grundkonzepte und Beispiele mit Code.  Teil 2 - 1Ich werde es selbst in der Intellij Idea Enterprise Edition machen. Alle meine Beispiele sollten aber auch in der kostenlosen Intellij Idea Community Edition funktionieren. Wenn Sie in den Screenshots sehen, dass ich eine Art Fenster habe, das Sie nicht haben, machen Sie sich keine Sorgen, es ist für dieses Projekt nicht kritisch :) Lassen Sie uns zunächst ein leeres Maven-Projekt erstellen. Wie das geht, habe ich im Artikel gezeigt (bis zu den Worten „ Es ist Zeit, unser Maven-Projekt in ein Webprojekt umzuwandeln “ lesen, danach wird bereits gezeigt, wie man ein Webprojekt erstellt, und das brauchen wir jetzt nicht) Erstellen wir es im Ordner src/main. /java ist ein Paket (in meinem Fall habe ich es „ ru.javarush.info.fatfaggy.animals“ genannt, Sie können es beliebig benennen, vergessen Sie nur nicht, es an den richtigen Stellen durch Ihren Namen zu ersetzen). Und erstellen wir eine Klasse, Mainin der wir eine Methode erstellen
public static void main(String[] args) {
    ...
}
Öffnen Sie dann die Datei pom.xml und fügen Sie dort einen Abschnitt hinzu dependencies. Jetzt gehen wir zum Maven-Repository und suchen dort nach dem Spring-Kontext der neuesten stabilen Version und fügen das, was wir haben, in den Abschnitt ein dependencies. Diesen Vorgang habe ich in diesem Artikel etwas ausführlicher beschrieben (siehe Abschnitt „ Abhängigkeiten in Maven verbinden “). Dann wird Maven selbst die notwendigen Abhängigkeiten finden und herunterladen, und am Ende sollten Sie etwa Folgendes erhalten:
Der Frühling ist etwas für Faule.  Grundlagen, Grundkonzepte und Beispiele mit Code.  Teil 2 - 2
Im linken Fenster sehen Sie die Struktur des Projekts mit Paket und Klasse Main. Das mittlere Fenster zeigt, wie meine pom.xml aussieht. Ich habe dort auch einen Eigenschaftenabschnitt hinzugefügt , in dem ich Maven angegeben habe, welche Java-Version ich im Quellcode verwende und in welche Version kompiliert werden soll. Dies nur, damit ich nicht auf die Idee komme, beim Starten eine Warnung zu erhalten, dass eine alte Java-Version verwendet wird. Sie können es tun, Sie können es nicht) Im rechten Fenster können Sie sehen, dass, obwohl wir nur den Spring-Kontext verbunden haben, automatisch Core, Beans, Aop und Expression hinzugefügt wurden. Es war möglich, jedes Modul separat zu verbinden und für jedes eine Abhängigkeit im Speicher mit einer expliziten Angabe der Version zu registrieren, aber im Moment sind wir mit der Option so, wie sie jetzt ist, zufrieden. Jetzt erstellen wir ein Paket entities(Entitäten) und erstellen darin drei Klassen: Cat, Dog, Parrot. Lassen Sie jedes Tier einen Namen haben ( private String name, Sie können dort einige Werte fest codieren), und die Getter/Setter sind öffentlich. Gehen Sie nun zur Klasse Mainund main()schreiben Sie so etwas in die Methode:
public static void main(String[] args) {
	// Erstelle einen leeren Spring-Kontext, der anhand von Annotationen im angegebenen Paket nach seinen Beans sucht
	ApplicationContext context =
		new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals.entities");

	Cat cat = context.getBean(Cat.class);
	Dog dog = (Dog) context.getBean("dog");
	Parrot parrot = context.getBean("parrot-kesha", Parrot.class);

	System.out.println(cat.getName());
	System.out.println(dog.getName());
	System.out.println(parrot.getName());
}
Zuerst erstellen wir ein Kontextobjekt und geben ihm im Konstruktor den Namen des Pakets, das auf das Vorhandensein von Beans überprüft werden soll. Das heißt, Spring geht dieses Paket durch und versucht, Klassen zu finden, die mit speziellen Annotationen gekennzeichnet sind, die Spring wissen lassen, dass es sich um eine Bean handelt. Anschließend erstellt es Objekte dieser Klassen und platziert sie in seinem Kontext. Danach bekommen wir eine Katze aus diesem Kontext. Wenn wir das Kontextobjekt ansprechen, bitten wir es, uns eine Bean (ein Objekt) zu geben und anzugeben, welche Objektklasse wir benötigen (hier können Sie übrigens nicht nur Klassen, sondern auch Schnittstellen angeben). Danach gibt uns Spring ein Objekt dieser Klasse zurück, das wir in einer Variablen speichern. Als nächstes bitten wir Spring, uns eine Bohne namens „Hund“ zu besorgen. Wenn Spring ein Klassenobjekt erstellt, Doggibt es ihm einen Standardnamen (wenn der Name der zu erstellenden Bean nicht explizit angegeben wird), der der Name der Klasse des Objekts ist, nur mit einem Kleinbuchstaben. Da unsere Klasse daher heißt Dog, lautet der Name einer solchen Bean „Hund“. Wenn wir dort ein Objekt hätten BufferedReader, würde Spring ihm den Standardnamen „bufferedReader“ geben. Und da es in diesem Fall (in Java) keine genaue Gewissheit darüber gibt, welche Klasse ein solches Objekt haben wird, gibt es einfach ein bestimmtes zurück Object, das wir dann manuell in den von uns benötigten Typ umwandeln Dog. Bequemer ist die Option mit expliziter Angabe der Klasse. Nun, im dritten Fall erhalten wir eine Bohne nach Klasse und Name. Es kann einfach eine Situation geben, in der es im Kontext mehrere Beans einer Klasse gibt, und um anzugeben, welche bestimmte Bean wir benötigen, geben wir ihren Namen an. Da wir hier auch die Klasse klar angegeben haben, müssen wir nicht mehr casten. Wichtig!Wenn sich herausstellt, dass Spring mehrere Beans gemäß den von uns angegebenen Anforderungen findet, kann es nicht bestimmen, welches Bean es uns geben soll, und löst eine Ausnahme aus. Versuchen Sie daher, ihm möglichst genau mitzuteilen, welchen Behälter Sie benötigen, damit es nicht zu solchen Situationen kommt. Wenn Spring gemäß Ihren Bedingungen keine einzelne Bean in seinem Kontext findet, wird ebenfalls eine Ausnahme ausgelöst. Dann zeigen wir einfach die Namen unserer Tiere auf dem Bildschirm an, um sicherzustellen, dass es sich tatsächlich um genau die Objekte handelt, die wir brauchen. Aber wenn wir das Programm jetzt ausführen, werden wir sehen, dass Spring schwört, dass es die Tiere, die wir brauchen, in seinem Kontext nicht finden kann. Dies geschah, weil er diese Bohnen nicht erschaffen hatte. Wie ich bereits sagte, sucht Spring beim Scannen von Klassen dort nach „seinen“ Spring-Annotationen. Und wenn es es nicht findet, dann erkennt es solche Klassen nicht als diejenigen, deren Beans er erstellen muss. Um dies zu beheben, fügen Sie in unseren Tierklassen einfach eine Anmerkung @Componentvor der Klasse hinzu.
@Component
public class Cat {
	private String name = „Barsik“;
	...
}
Aber das ist nicht alles. Wenn wir Spring explizit mitteilen müssen, dass die Bean für diese Klasse einen bestimmten Namen haben soll, kann dieser Name in Klammern nach der Annotation angegeben werden. Damit Spring beispielsweise parrot-keshader Papageienbohne, von der wir mainspäter diesen Papagei erhalten, den Namen geben kann, den wir benötigen, müssen wir etwa Folgendes tun:
@Component("parrot-kesha")
public class Parrot {
	private String name = „Kesha“;
	...
}
Das ist der Sinn der automatischen Konfiguration . Sie schreiben Ihre Klassen, markieren sie mit den notwendigen Annotationen und geben Spring ein Paket mit Ihren Klassen an, durch das es geht, nach Annotationen sucht und Objekte solcher Klassen erstellt. Übrigens durchsucht Spring nicht nur Annotationen @Component, sondern auch alle anderen Annotationen, die von dieser geerbt werden. Zum Beispiel , , , @Controllerund @RestControllerandere , die wir in weiteren Artikeln kennenlernen werden. Versuchen wir nun, dasselbe zu tun, verwenden jedoch die Java-Konfiguration . Entfernen wir zunächst Anmerkungen aus unseren Klassen. Um die Aufgabe zu verkomplizieren, stellen wir uns vor, dass es sich nicht um unsere eigenen, selbst geschriebenen Klassen handelt, die wir leicht ändern und etwas hinzufügen können, einschließlich Anmerkungen. Es ist, als ob diese Klassen in einer Bibliothek verstaut wären. In diesem Fall können wir diese Klassen in keiner Weise bearbeiten, damit sie von Spring akzeptiert werden. Aber wir brauchen Objekte dieser Klassen! Hier benötigen wir die Java-Konfiguration, um solche Objekte zu erstellen. Erstellen wir zunächst ein Paket, zum Beispiel und darin – zum Beispiel eine reguläre Java-Klasse, und markieren wir es mit einer Anmerkung@Service@Repository@ComponentconfigsMyConfig@Configuration
@Configuration
public class MyConfig {
}
Jetzt müssen wir main()die Art und Weise, wie wir den Kontext in der Methode erstellen, leicht anpassen. Wir können dort entweder direkt unsere Klasse mit Konfiguration angeben:
ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class);
Wenn wir mehrere verschiedene Klassen haben, in denen wir Beans erstellen, und mehrere davon gleichzeitig verbinden möchten, geben wir sie dort einfach durch Kommas getrennt an:
ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class, MyAnotherConfig.class);
Wenn wir zu viele davon haben und sie alle auf einmal verbinden möchten, geben wir hier einfach den Namen des Pakets an, in dem wir sie haben:
ApplicationContext context =
	new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals.configs");
In diesem Fall durchsucht Spring dieses Paket und findet alle Klassen, die mit der Annotation gekennzeichnet sind @Configuration. Wenn wir ein wirklich großes Programm haben, bei dem die Konfigurationen in verschiedene Pakete unterteilt sind, geben wir einfach die Namen der Pakete mit durch Kommas getrennten Konfigurationen an:
ApplicationContext context =
	new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals.database.configs",
		"ru.javarush.info.fatfaggy.animals.root.configs",
		"ru.javarush.info.fatfaggy.animals.web.configs");
Nun, oder der Name eines Pakets, das allen gemeinsam ist:
ApplicationContext context =
	new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals");
Sie können es machen, wie Sie möchten, aber mir scheint, dass die allererste Option, bei der Sie einfach eine Klasse mit Konfigurationen angeben, am besten zu unserem Programm passt. Beim Erstellen eines Kontexts sucht Spring nach den Klassen, die mit der Annotation markiert sind @Configuration, und erstellt in sich selbst Objekte dieser Klassen. Anschließend wird versucht, Methoden in diesen Klassen aufzurufen, die mit der Annotation gekennzeichnet sind @Bean. Das bedeutet, dass solche Methoden Beans (Objekte) zurückgeben, die bereits in ihren Kontext eingefügt wurden. Nun erstellen wir in unserem Kurs Katzen-, Hunde- und Papageienbohnen mit Java-Konfiguration. Das geht ganz einfach:
@Bean
public Cat getCat() {
	return new Cat();
}
Es stellt sich heraus, dass wir unsere Katze manuell selbst erstellt und Spring gegeben haben, und er hat dieses Objekt von uns bereits in seinen Kontext gestellt. Da wir den Namen unserer Bean nicht explizit angegeben haben, gibt Spring der Bean denselben Namen wie den Namen der Methode. In unserem Fall wird die Katzenbohne den Namen „ getCat“ haben. Aber da mainwir in -e die Katze immer noch nicht nach Namen, sondern nach Klasse bekommen, ist uns in diesem Fall der Name dieses Behälters nicht wichtig. Machen Sie auf die gleiche Weise eine Bohne mit einem Hund, aber denken Sie daran, dass Spring eine solche Bohne nach dem Namen der Methode benennen wird. Um unsere Bohne explizit mit dem Papagei zu benennen, geben Sie einfach ihren Namen in Klammern nach der Anmerkung an @Bean:
@Bean("parrot-kesha")
public Object weNeedMoreParrots() {
	return new Parrot();
}
Wie Sie sehen können, habe ich hier den Typ des Rückgabewerts angegeben Objectund die Methode beliebig aufgerufen. Dies hat keinerlei Auswirkungen auf den Namen der Bean, da wir ihn hier explizit festlegen. Es ist jedoch besser, den Rückgabewerttyp und den Methodennamen nicht aus heiterem Himmel, sondern mehr oder weniger deutlich anzugeben. Nur für Sie selbst, wenn Sie dieses Projekt in einem Jahr eröffnen. :) Betrachten wir nun eine Situation, in der wir zum Erstellen einer Bean eine andere Bean verwenden müssen . Beispielsweise möchten wir, dass der Name der Katze in der Katzenbohne aus dem Namen des Papageis und der Zeichenfolge „-killer“ besteht. Kein Problem!
@Bean
public Cat getCat(Parrot parrot) {
	Cat cat = new Cat();
	cat.setName(parrot.getName() + "-killer");
	return cat;
}
Hier wird Spring erkennen, dass er vor dem Erstellen dieser Bohne die bereits erstellte Papageienbohne hierher übertragen muss. Daher wird er eine Kette von Aufrufen unserer Methoden erstellen, sodass zuerst die Methode zum Erstellen eines Papageis aufgerufen wird und dieser Papagei dann an die Methode zum Erstellen einer Katze übergeben wird. Hier funktionierte die sogenannte Abhängigkeitsinjektion : Spring selbst übergab die erforderliche Papageienbohne an unsere Methode. Wenn sich die Idee über eine Variable beschwert parrot, vergessen Sie nicht, den Rückgabetyp in der Methode zum Erstellen eines Papageis von Objectin zu ändern Parrot. Darüber hinaus können Sie mit der Java-Konfiguration absolut jeden Java-Code in Methoden zum Erstellen von Beans ausführen . Man kann wirklich alles machen: andere Hilfsobjekte erstellen, beliebige andere Methoden aufrufen, auch solche, die nicht mit Spring-Annotationen gekennzeichnet sind, Schleifen erstellen, Bedingungen erstellen – was immer einem in den Sinn kommt! All dies kann nicht mit der automatischen Konfiguration erreicht werden, geschweige denn mit XML-Konfigurationen. Schauen wir uns nun ein interessanteres Problem an. Mit Polymorphismus und Schnittstellen :) Lassen Sie uns eine Schnittstelle erstellen WeekDayund 7 Klassen erstellen, die diese Schnittstelle implementieren würden: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday. Erstellen wir eine Methode in der Schnittstelle String getWeekDayName(), die den Namen des Wochentags der entsprechenden Klasse zurückgibt. Das heißt, die Klasse Mondaywürde „ monday“ usw. zurückgeben. Nehmen wir an, die Aufgabe beim Starten unserer Anwendung besteht darin, eine Bean in den Kontext zu platzieren, der dem aktuellen Wochentag entspricht. Nicht alle Beans aller Klassen, die WeekDaydie Schnittstelle implementieren, sondern nur die, die wir brauchen. Das kann man etwa so machen:
@Bean
public WeekDay getDay() {
	DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
	switch (dayOfWeek) {
		case MONDAY: return new Monday();
		case TUESDAY: return new Tuesday();
		case WEDNESDAY: return new Wednesday();
		case THURSDAY: return new Thursday();
		case FRIDAY: return new Friday();
		case SATURDAY: return new Saturday();
		default: return new Sunday();
	}
}
Hier ist der Rückgabewerttyp unsere Schnittstelle, und die Methode gibt abhängig vom aktuellen Wochentag reale Objekte der Schnittstellenimplementierungsklassen zurück. main()Jetzt können wir in der Methode Folgendes tun:
WeekDay weekDay = context.getBean(WeekDay.class);
System.out.println("It's " + weekDay.getWeekDayName() + " today!");
Mir wurde gesagt, dass heute Sonntag ist :) Ich bin mir sicher, dass, wenn ich das Programm morgen ausführe, ein völlig anderes Objekt im Kontext erscheinen wird. Bitte beachten Sie, dass wir hier die Bean einfach über die Schnittstelle erhalten: context.getBean(WeekDay.class). Spring prüft in seinem Kontext, welche seiner Beans eine solche Schnittstelle implementiert und gibt sie zurück. Nun, dann stellt sich heraus, dass WeekDayes in einer Variablen vom Typ ein Objekt vom Typ gibt Sundayund der Polymorphismus, der uns allen bereits bekannt ist, beginnt, wenn mit dieser Variablen gearbeitet wird. :) Und ein paar Worte zum kombinierten Ansatz , bei dem einige der Beans von Spring selbst erstellt werden, indem Pakete auf das Vorhandensein von Klassen mit einer Annotation gescannt werden @Component, und einige andere Beans mithilfe der Java-Konfiguration erstellt werden. Gehen wir dazu zurück zur Originalversion, als die Klassen Cat, Dogund Parrotmit einer Annotation markiert waren @Component. Nehmen wir an, wir möchten bis zum Frühjahr Behälter für unsere Tiere erstellen, indem wir das Paket automatisch scannenentities , erstellen aber wie gerade einen Behälter mit dem Wochentag. Alles, was Sie tun müssen, ist, auf Klassenebene hinzuzufügen MyConfig, die wir beim Erstellen des Kontexts in mainder -ten Annotation angeben @ComponentScan, und in Klammern das Paket anzugeben, das gescannt werden muss, sowie die Beans der erforderlichen Klassen, die automatisch erstellt werden:
@Configuration
@ComponentScan("ru.javarush.info.fatfaggy.animals.entities")
public class MyConfig {
	@Bean
	public WeekDay getDay() {
		DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
		switch (dayOfWeek) {
			case MONDAY: return new Monday();
			case TUESDAY: return new Tuesday();
			case WEDNESDAY: return new Wednesday();
			case THURSDAY: return new Thursday();
			case FRIDAY: return new Friday();
			case SATURDAY: return new Saturday();
			default: return new Sunday();
		}
	}
}
Es stellt sich heraus, dass Spring beim Erstellen eines Kontexts erkennt, dass die Klasse verarbeitet werden muss MyConfig. Er geht hinein und stellt fest, dass er das Paket „ ru.javarush.info.fatfaggy.animals.entities“ scannen und Beans dieser Klassen erstellen muss. Anschließend führt er eine Methode getDay()der Klasse aus und fügt seinem Kontext MyConfigein Bean dieses Typs hinzu . WeekDayIn der Methode main()haben wir nun Zugriff auf alle Beans, die wir benötigen: sowohl die Tierobjekte als auch die Wochentag-Bean. So stellen Sie sicher, dass Spring auch einige XML-Konfigurationen aufnimmt – googeln Sie es selbst im Internet, wenn Sie es brauchen :) Zusammenfassung:
  • Versuchen Sie, die automatische Konfiguration zu verwenden.
  • Bei der automatischen Konfiguration geben wir den Namen des Pakets an, das die Klassen enthält, deren Beans erstellt werden müssen.
  • Solche Klassen sind mit einer Anmerkung gekennzeichnet@Component;
  • spring durchläuft alle diese Klassen, erstellt ihre Objekte und stellt sie in den Kontext;
  • Wenn uns die automatische Konfiguration aus irgendeinem Grund nicht zusagt, verwenden wir die Java-Konfiguration.
  • In diesem Fall erstellen wir eine reguläre Java-Klasse, deren Methoden die von uns benötigten Objekte zurückgeben, und markieren eine solche Klasse mit einer Anmerkung @Configurationfür den Fall, dass wir das gesamte Paket scannen, anstatt beim Erstellen des Kontexts eine bestimmte Klasse mit Konfiguration anzugeben;
  • Methoden dieser Klasse, die Beans zurückgeben, sind mit der Annotation gekennzeichnet @Bean;
  • Wenn wir das automatische Scannen bei Verwendung der Java-Konfiguration aktivieren möchten, verwenden wir die Annotation @ComponentScan.
Wenn nichts klar ist, versuchen Sie, diesen Artikel in ein paar Tagen zu lesen. Nun ja, oder wenn Sie sich auf einem frühen Javarash-Niveau befinden, dann ist es vielleicht etwas früh für Sie, den Frühling zu lernen. Sie können jederzeit zu einem späteren Zeitpunkt zu diesem Artikel zurückkehren, wenn Sie sich beim Programmieren in Java sicherer fühlen. Wenn alles klar ist, können Sie versuchen, einige Ihrer Lieblingsprojekte auf Spring zu übertragen :) Wenn etwas klar ist, aber etwas nicht so sehr, kommentieren Sie es bitte :) Es gibt auch Vorschläge und Kommentare, wenn ich irgendwo hingetreten bin oder etwas Dummes geschrieben habe ) Im nächsten Artikel werden wir uns eingehend mit spring-web-mvc befassen und mit Spring eine einfache Webanwendung erstellen.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION