JavaRush /Blog Java /Random-PL /Wiosna jest dla leniwych. Podstawy, podstawowe pojęcia i ...
Стас Пасинков
Poziom 26
Киев

Wiosna jest dla leniwych. Podstawy, podstawowe pojęcia i przykłady z kodem. Część 2

Opublikowano w grupie Random-PL
W ostatnim artykule wyjaśniłem w skrócie czym jest wiosna, czym są kosze i kontekst. Teraz czas wypróbować jak to wszystko działa. Wiosna jest dla leniwych.  Podstawy, podstawowe pojęcia i przykłady z kodem.  Część 2 - 1Zrobię to sam w Intellij Idea Enterprise Edition. Ale wszystkie moje przykłady powinny również działać w bezpłatnej wersji Intellij Idea Community Edition. Jeśli tylko zobaczysz na zrzutach ekranu, że mam jakieś okno, którego ty nie masz, nie martw się, nie jest to krytyczne dla tego projektu :) Najpierw utwórzmy pusty projekt Mavena. Pokazałem, jak to zrobić w artykule (czytaj aż do słów „ Nadszedł czas, aby zamienić nasz projekt maven w projekt internetowy ”. Potem już pokazano, jak stworzyć projekt internetowy i nie potrzebujemy tego teraz) Stwórzmy go w folderze src/main /java to jakiś pakiet (w moim przypadku nazwałem go „ ru.javarush.info.fatfaggy.animals”, możesz go nazwać jak chcesz, tylko nie zapomnij zastąpić go swoim imieniem w odpowiednich miejscach). I utwórzmy klasę Main, w której zrobimy metodę
public static void main(String[] args) {
    ...
}
Następnie otwórz plik pom.xml i dodaj tam sekcję dependencies. Teraz udajemy się do repozytorium Mavena i szukamy tam wiosennego kontekstu najnowszej stabilnej wersji, a to co otrzymaliśmy wklejamy wewnątrz sekcji dependencies. Nieco szerzej opisałem ten proces w tym artykule (patrz sekcja „ Łączenie zależności w Maven ”). Następnie sam Maven znajdzie i pobierze niezbędne zależności, a na koniec powinieneś otrzymać coś takiego:
Wiosna jest dla leniwych.  Podstawy, podstawowe pojęcia i przykłady z kodem.  Część 2 - 2
W lewym oknie możesz zobaczyć strukturę projektu z pakietem i klasą Main. Środkowe okno pokazuje, jak wygląda mój plik pom.xml. Dodałem tam również sekcję właściwości , w której wskazałem Mavenowi, jakiej wersji Javy używam w kodzie źródłowym i do której wersji się kompiluję. Dzieje się tak po to, żebym nie wpadł na pomysł ostrzeżenia podczas uruchamiania, że ​​używana jest stara wersja Java. Możesz to zrobić, nie możesz) W prawym oknie - widać, że pomimo tego, że podłączyliśmy tylko kontekst wiosenny - automatycznie dodał on rdzeń, fasolę, aop i wyrażenie. Można było podłączyć każdy moduł osobno, rejestrując dla każdego zależność w pamięci z wyraźnym wskazaniem wersji, ale na razie zadowala nas taka opcja, jaka jest obecnie. Stwórzmy teraz pakiet entities(jednostki) i utwórzmy w nim 3 klasy: Cat, Dog, Parrot. Niech każde zwierzę ma nazwę ( private String name, możesz tam zakodować na stałe pewne wartości), a moduły pobierające/ustawiające są publiczne. Teraz idź do klasy Maini main()napisz w metodzie coś takiego:
public static void main(String[] args) {
	// utwórz pusty kontekst wiosenny, który będzie szukał swoich komponentów według adnotacji w określonym pakiecie
	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());
}
Najpierw tworzymy obiekt kontekstowy i w konstruktorze nadajemy mu nazwę pakietu, który należy przeskanować pod kątem obecności ziaren. Oznacza to, że Spring przejrzy ten pakiet i spróbuje znaleźć klasy oznaczone specjalnymi adnotacjami, które informują Springa, że ​​jest to komponent bean. Następnie tworzy obiekty tych klas i umieszcza je w swoim kontekście. Po czym dostajemy kota z tego kontekstu. Zwracając się do obiektu kontekstu, prosimy go o podanie nam fasoli (obiektu) i wskazanie jakiej klasy obiektu potrzebujemy (tutaj, notabene, można określić nie tylko klasy, ale także interfejsy). Po czym Spring zwraca nam obiekt tej klasy, który zapisujemy w zmiennej. Następnie prosimy Springa, aby przyniósł nam fasolę o imieniu „pies”. Kiedy Spring tworzy obiekt klasy, Dognada mu standardową nazwę (jeśli nazwa tworzonego komponentu nie jest wyraźnie określona), która jest nazwą klasy obiektu, tylko z małą literą. Dlatego, ponieważ nasza klasa nazywa się Dog, nazwa takiego fasoli będzie brzmieć „pies”. Gdybyśmy mieli tam obiekt BufferedReader, Spring nadałby mu domyślną nazwę „bufferedReader”. A ponieważ w tym przypadku (w Javie) nie ma całkowitej pewności, jakiej klasy będzie taki obiekt, po prostu zwraca określony Object, który następnie ręcznie rzutujemy na potrzebny nam typ Dog. Wygodniejsza jest opcja z wyraźnym wskazaniem klasy. Cóż, w trzecim przypadku fasolę otrzymujemy według klasy i nazwy. Może po prostu zaistnieć sytuacja, że ​​w kontekście będzie kilka ziaren jednej klasy i aby wskazać jakiego konkretnego fasola potrzebujemy, podajemy jego nazwę. Ponieważ tutaj również wyraźnie wskazaliśmy klasę, nie musimy już rzucać. Ważny!Jeśli okaże się, że Spring znajdzie kilka fasoli zgodnie z wymaganiami, które mu postawiliśmy, to nie będzie w stanie określić, który fasolę nam dać i zgłosi wyjątek. Dlatego staraj się mu jak najdokładniej wskazać, jakiego kosza potrzebujesz, aby takie sytuacje nie miały miejsca. Jeśli Spring nie znajdzie ani jednej fasoli w swoim kontekście zgodnie z twoimi warunkami, również zgłosi wyjątek. Cóż, wtedy po prostu wyświetlamy na ekranie imiona naszych zwierząt, aby mieć pewność, że są to dokładnie te obiekty, których potrzebujemy. Ale jeśli uruchomimy program teraz, zobaczymy, że Wiosna przysięga, że ​​nie może znaleźć zwierząt, których potrzebujemy w swoim kontekście. Stało się tak, ponieważ to nie on stworzył te ziarna. Jak już mówiłem, kiedy Spring skanuje klasy, szuka tam „swoich” adnotacji Springa. A jeśli go nie znajdzie, to nie postrzega takich klas jako tych, których fasolę musi stworzyć. Aby to naprawić, po prostu dodaj adnotację @Componentprzed klasą w naszych klasach zwierząt.
@Component
public class Cat {
	private String name = "Barsik";
	...
}
Ale to nie wszystko. Jeśli musimy wyraźnie wskazać Springowi, że komponent bean tej klasy powinien mieć konkretną nazwę, nazwę tę można podać w nawiasie po adnotacji. Przykładowo, żeby Spring nadał potrzebną nazwę parrot-keshafasolce papugowej, z której mainpóźniej otrzymamy tę papugę, musimy zrobić coś takiego:
@Component("parrot-kesha")
public class Parrot {
	private String name = "Kesza";
	...
}
Na tym polega cały sens automatycznej konfiguracji . Piszesz swoje klasy, zaznaczasz je niezbędnymi adnotacjami i wskazujesz Springowi pakiet ze swoimi klasami, przez który przechodzi, szuka adnotacji i tworzy obiekty takich klas. Nawiasem mówiąc, Spring będzie przeszukiwał nie tylko adnotacje @Component, ale także wszystkie inne adnotacje odziedziczone z tej. Na przykład , @Controller, @RestController, i inne @Service, @Repositoryktóre poznamy w kolejnych artykułach. Teraz spróbujmy zrobić to samo, ale używając konfiguracji Java . Najpierw usuńmy adnotacje @Componentz naszych zajęć. Aby skomplikować zadanie, wyobraźmy sobie, że nie są to własne, napisane przez nas klasy, które możemy łatwo zmodyfikować, dodać coś, łącznie z adnotacjami. To tak, jakby te zajęcia były upchane w jakiejś bibliotece. W takim przypadku nie możemy w żaden sposób edytować tych zajęć, aby do wiosny zostały zaakceptowane. Ale potrzebujemy obiektów tych klas! Tutaj będziemy potrzebować konfiguracji Java, aby utworzyć takie obiekty. Na początek utwórzmy pakiet, configsa w nim np. zwykłą klasę Java MyConfigi oznaczmy go adnotacją@Configuration
@Configuration
public class MyConfig {
}
Teraz musimy nieco zmodyfikować main()sposób tworzenia kontekstu w metodzie. Możemy bezpośrednio określić naszą klasę z konfiguracją:
ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class);
Jeśli mamy kilka różnych klas, w których tworzymy fasole i chcemy połączyć kilka z nich na raz, po prostu je tam wskazujemy, oddzielając je przecinkami:
ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class, MyAnotherConfig.class);
Otóż, jeśli mamy ich za dużo, a chcemy połączyć je wszystkie na raz, po prostu wskazujemy tutaj nazwę pakietu, w którym je mamy:
ApplicationContext context =
	new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals.configs");
W tym przypadku Spring przejrzy ten pakiet i znajdzie wszystkie klasy oznaczone adnotacją @Configuration. Cóż, w przypadku, gdy mamy naprawdę duży program, w którym konfiguracje są podzielone na różne pakiety, po prostu wskazujemy nazwy pakietów z konfiguracjami oddzielonymi przecinkami:
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");
Cóż, albo nazwa pakietu bardziej wspólna dla nich wszystkich:
ApplicationContext context =
	new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals");
Możesz to zrobić, jak chcesz, ale wydaje mi się, że pierwsza opcja, w której po prostu określisz klasę z konfiguracjami, będzie najlepiej pasować do naszego programu. Tworząc kontekst, Spring będzie szukał tych klas, które są oznaczone adnotacją @Configurationi sam w sobie tworzy obiekty tych klas. Po czym spróbuje wywołać metody w tych klasach, które są oznaczone adnotacją @Bean, co oznacza, że ​​takie metody zwrócą komponenty (obiekty), które umieścił już w swoim kontekście. Cóż, teraz utwórzmy fasolę dla kotów, psów i papug w naszej klasie z konfiguracją Java. Odbywa się to po prostu:
@Bean
public Cat getCat() {
	return new Cat();
}
Okazuje się, że sami własnoręcznie stworzyliśmy naszego kota i podarowaliśmy go Springowi, a on już umieścił ten nasz obiekt w swoim kontekście. Ponieważ nie określiliśmy jawnie nazwy naszego komponentu, Spring nada mu taką samą nazwę, jak nazwa metody. W naszym przypadku kocia fasola będzie miała nazwę „ getCat”. Ale ponieważ w main-e nadal dostajemy kota nie po imieniu, ale po klasie, to w tym przypadku nazwa tego kosza nie jest dla nas ważna. W ten sam sposób zrób fasolkę z psem, ale pamiętaj, że Spring nazwie taką fasolkę nazwą metody. Aby jednoznacznie nazwać naszą fasolkę papugą, wystarczy podać jej nazwę w nawiasie po adnotacji @Bean:
@Bean("parrot-kesha")
public Object weNeedMoreParrots() {
	return new Parrot();
}
Jak widać, tutaj wskazałem typ zwracanej wartości Object, a metodę w ogóle nazwałem. Nie wpływa to w żaden sposób na nazwę komponentu bean, ponieważ wyraźnie ją tutaj ustawiliśmy. Lepiej jednak wskazać typ wartości zwracanej i nazwę metody nie od razu, ale mniej lub bardziej wyraźnie. Nawet dla siebie, gdy za rok otworzysz ten projekt. :) Rozważmy teraz sytuację, w której do stworzenia jednego komponentu bean musimy użyć innego komponentu bean . Na przykład chcemy, aby imię kota w fasoli kota składało się z imienia papugi i ciągu „-killer”. Bez problemu!
@Bean
public Cat getCat(Parrot parrot) {
	Cat cat = new Cat();
	cat.setName(parrot.getName() + "-killer");
	return cat;
}
Tutaj Spring zobaczy, że przed utworzeniem tej fasoli będzie musiał przenieść tutaj już utworzoną fasolkę papugą. Dlatego zbuduje łańcuch wywołań naszych metod, aby najpierw wywołać metodę tworzenia papugi, a następnie przekazać tę papugę do metody tworzenia kota. Tutaj zadziałało zjawisko zwane wstrzykiwaniem zależności : Spring sam przekazał wymaganą fasolę papugą do naszej metody. Jeśli pomysł skarży się na zmienną parrot, nie zapomnij zmienić typu zwracanego w metodzie tworzenia papugi z Objectna Parrot. Dodatkowo konfiguracja Java pozwala na wykonanie absolutnie dowolnego kodu Java w metodach tworzenia ziaren. Można tak naprawdę wszystko: tworzyć inne obiekty pomocnicze, wywoływać dowolne inne metody, nawet te nieoznaczone adnotacjami sprężynowymi, tworzyć pętle, warunki – cokolwiek przyjdzie do głowy! Tego wszystkiego nie można osiągnąć za pomocą automatycznej konfiguracji, a tym bardziej za pomocą konfiguracji XML. Teraz spójrzmy na bardziej zabawny problem. Z polimorfizmem i interfejsami :) Stwórzmy interfejs WeekDayi stwórzmy 7 klas, które implementowałyby ten interfejs: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday. Stwórzmy w interfejsie metodę String getWeekDayName(), która zwróci nazwę dnia tygodnia odpowiedniej klasy. Oznacza to, że klasa Mondayzwróci „ monday” itd. Załóżmy, że zadaniem przy uruchomieniu naszej aplikacji jest umieszczenie fasoli w kontekście, który odpowiadałby aktualnemu dniu tygodnia. Nie wszystkie komponenty bean wszystkich klas, które implementują WeekDayinterfejs, ale tylko ten, którego potrzebujemy. Można to zrobić mniej więcej tak:
@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();
	}
}
Tutaj typem wartości zwracanej jest nasz interfejs, a metoda zwraca rzeczywiste obiekty klas implementacji interfejsu w zależności od aktualnego dnia tygodnia. Teraz w metodzie main()możemy to zrobić:
WeekDay weekDay = context.getBean(WeekDay.class);
System.out.println("It's " + weekDay.getWeekDayName() + " today!");
Powiedziało mi, że dzisiaj jest niedziela :) Jestem pewien, że jeśli jutro uruchomię program, w kontekście pojawi się zupełnie inny obiekt. Należy pamiętać, że tutaj fasolę dostajemy po prostu przez interfejs: context.getBean(WeekDay.class). Spring sprawdzi w swoim kontekście, które z jego ziaren implementuje taki interfejs i zwróci go. No cóż, wtedy okazuje się, że WeekDayw zmiennej typu znajduje się obiekt typu Sunday, a polimorfizm, znany już każdemu z nas, zaczyna się podczas pracy z tą zmienną. :) I kilka słów o podejściu kombinowanym , gdzie część ziaren tworzy sam Spring, skanując pakiety pod kątem obecności klas z adnotacją @Component, a część innych fasoli tworzy przy użyciu konfiguracji Java. Aby to zrobić, wróćmy do wersji oryginalnej, kiedy klasy Cati Dogzostały Parrotoznaczone adnotacją @Component. Załóżmy, że chcemy stworzyć pojemniki dla naszych zwierząt za pomocą automatycznego skanowania paczki entitiesna wiosnę, ale tak jak to zrobiliśmy, utwórz pojemnik z dniem tygodnia. Wystarczy dodać na poziomie klasy MyConfig, którą podajemy podczas tworzenia kontekstu w main-tej adnotacji @ComponentScan, a w nawiasie wskazać pakiet, który ma zostać przeskanowany oraz komponenty potrzebnych klas utworzone automatycznie:
@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();
		}
	}
}
Okazuje się, że Spring tworząc kontekst widzi, że musi przetworzyć klasę MyConfig. Wchodzi w to i widzi, że musi przeskanować pakiet „ ru.javarush.info.fatfaggy.animals.entities” i utworzyć komponenty bean tych klas, po czym wykonuje metodę getDay()z klasy MyConfigi dodaje komponent bean typu WeekDaydo swojego kontekstu. W tej metodzie main()mamy teraz dostęp do wszystkich potrzebnych nam ziaren: zarówno obiektów zwierzęcych, jak i fasoli z dniem tygodnia. Jak upewnić się, że Spring pobiera również niektóre konfiguracje XML - w razie potrzeby samodzielnie poszukaj tego w Internecie :) Podsumowanie:
  • spróbuj użyć konfiguracji automatycznej;
  • podczas konfiguracji automatycznej podajemy nazwę pakietu zawierającego klasy, których komponenty mają zostać utworzone;
  • klasy takie oznaczone są adnotacją@Component;
  • wiosna przechodzi przez wszystkie takie klasy, tworzy ich obiekty i umieszcza je w kontekście;
  • jeśli z jakiegoś powodu automatyczna konfiguracja nam nie odpowiada, korzystamy z konfiguracji Java;
  • w tym przypadku tworzymy zwykłą klasę Java, której metody zwrócą potrzebne nam obiekty i zaznaczamy taką klasę adnotacją @Configurationna wypadek, gdybyśmy przeskanowali cały pakiet, zamiast podawać konkretną klasę z konfiguracją podczas tworzenia kontekstu;
  • metody tej klasy zwracające komponenty bean są oznaczone adnotacją @Bean;
  • jeśli chcemy włączyć automatyczne skanowanie podczas korzystania z konfiguracji Java, używamy adnotacji @ComponentScan.
Jeśli nic nie jest jasne, spróbuj przeczytać ten artykuł za kilka dni. Cóż, jeśli jesteś na wczesnym poziomie Javarasha, być może jest trochę za wcześnie, abyś nauczył się wiosny. Zawsze możesz wrócić do tego artykułu nieco później, gdy poczujesz się pewniej w programowaniu w Javie. Jeśli wszystko jest jasne, możesz spróbować przenieść niektóre swoje ulubione projekty na wiosnę :) Jeśli coś jest jasne, ale coś nie bardzo, proszę o komentarz :) Są też sugestie i komentarze, jeśli gdzieś wkroczyłem lub napisałem coś głupiego ) W następnym artykule zagłębimy się w Spring-web-mvc i stworzymy prostą aplikację internetową przy użyciu Springa.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION