CodeGym /Blog Java /Random-PL /Wiosna dla leniwych Podstawy, podstawowe pojęcia i przykł...
John Squirrels
Poziom 41
San Francisco

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

Opublikowano w grupie Random-PL
W poprzednim artykule pokrótce wyjaśniłem, czym jest Spring i czym są fasole i kontekst. Teraz nadszedł czas, aby go wypróbować. Zamierzam to zrobić za pomocą IntelliJ IDEA Enterprise Edition. Ale wszystkie moje przykłady powinny również działać w bezpłatnej wersji IntelliJ IDEA Community Edition. Jeśli na zrzutach ekranu widzisz, że mam jakieś okno, którego ty nie masz, nie martw się — nie jest to ważne dla tego projektu :) Wiosna dla leniwych Podstawy, podstawowe pojęcia i przykłady z kodem.  Część 2 - 1Najpierw utwórz pusty projekt Maven. Pokazałem jak to zrobić w artykule pod tym linkiem . Przeczytaj do słów „ Nadszedł czas, abyśmy przekonwertowali nasz projekt Maven na projekt internetowy ”. Następnie artykuł pokazuje, jak zrobić projekt internetowy, ale nie potrzebujemy go teraz. W src/main/javafolder, utwórz pakiet (w moim przypadku nazwałem go „ en.codegym.info.fatfaggy.animals. Możesz go nazwać, jak chcesz. Tylko nie zapomnij zastąpić mojej nazwy pakietu nazwą swojego pakietu we wszystkich właściwych miejscach. Teraz utwórz klasę Maini dodaj metoda

public static void main(String[] args) {
    ...
}
Następnie otwórz plik pom.xml i dodaj sekcję dependencies. Teraz przejdź do repozytorium Maven i znajdź kontekst Spring dla najnowszej stabilnej wersji. Umieść to, co znaleźliśmy w dependenciessekcji. Opisałem ten proces bardziej szczegółowo w tym innym artykule CodeGym (patrz sekcja zatytułowana „ Łączenie zależności w Maven ”). Wtedy sam Maven znajdzie i pobierze potrzebne zależności. Ostatecznie powinieneś otrzymać coś takiego: Wiosna dla leniwych Podstawy, podstawowe pojęcia i przykłady z kodem.  Część 2 - 2W oknie po lewej stronie możesz zobaczyć strukturę projektu z pakietem i klasą Main. Środkowe okno pokazuje, jak wygląda dla mnie pom.xml. Dodałem również właściwościsekcja do niego. Ta sekcja mówi Mavenowi, której wersji Javy używam w moich plikach źródłowych i którą wersję mam skompilować. Dzieje się tak, aby IDEA nie ostrzegała mnie, że używam starej wersji Javy. Jest to opcjonalne :) Prawe okno wyjaśnia, że ​​chociaż podłączyliśmy tylko moduł spring-context, automatycznie wciągnął on moduły spring-core, spring-beans, spring-aop i spring-expression. Mogliśmy podłączyć każdy moduł osobno, wypisując zależności dla każdego modułu z jawną wersją w pliku pom.xml, ale na razie jesteśmy zadowoleni z rzeczy, jakie są. Teraz utwórz entitiespakiet i utwórz w nim 3 klasy: Cat, Dog, Parrot. Nadajmy każdemu zwierzęciu imię (private String name— możesz tam zakodować niektóre wartości). Moduły pobierające/ustawiające są publiczne. Teraz przechodzimy do Mainklasy i main()metody i piszemy coś takiego:

public static void main(String[] args) {
	// Create an empty Spring context that will look for its own beans based on the annotations in the specified package
	ApplicationContext context = 
		new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.entities");

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

	System.out.println(cat.getName());
	System.out.println(dog.getName());
	System.out.println(parrot.getName());
}
Najpierw tworzymy obiekt kontekstu, informujący konstruktora, w którym pakiecie ma szukać komponentów bean. Innymi słowy, Spring przejrzy ten pakiet i spróbuje znaleźć klasy oznaczone specjalnymi adnotacjami, które wskazują, że są to fasole. Następnie tworzy obiekty tych klas i umieszcza je w kontekście. Następnie otrzymujemy kota z tego kontekstu. Wywołujemy obiekt kontekstu, aby dał nam fasolę (obiekt), wskazując klasę żądanego obiektu (nawiasem mówiąc, możemy również określić interfejsy, a nie tylko klasy). Następnie Spring zwraca obiekt żądanej klasy, który następnie zapisujemy w zmiennej. Następnie prosimy Springa o fasolkę o nazwie „pies”. Kiedy Spring tworzyDogobiekt, nadaje obiektowi standardową nazwę (chyba że utworzonemu komponentowi beanowi została jawnie przypisana nazwa), która jest nazwą klasy, ale z małą literą na początku. W tym przypadku nasza klasa nazywa się Dog, więc nazwa fasoli brzmi „pies”. Gdybyśmy potrzebowali BufferedReadertam obiektu, Spring nazwałby go „bufferedReader”. A ponieważ Java nie może być w 100% pewna, której klasy chcemy, zwraca obiekt Object, który następnie ręcznie rzutujemy na żądany typ, tj.Dog. Opcja, w której klasa jest wskazana jawnie, jest wygodniejsza. Trzecią opcją jest pobranie fasoli według nazwy klasy i nazwy fasoli. Możliwe, że kontekst może mieć kilka komponentów jednej klasy. Aby wskazać konkretną fasolę, której potrzebujemy, podajemy jej nazwę. Ponieważ tutaj również wyraźnie wskazujemy klasę, nie musimy już wykonywać rzutowania. WAŻNY!Jeśli Spring znajdzie kilka ziaren spełniających nasze wymagania, nie może określić, który z nich nam dać, więc zgłosi wyjątek. W związku z tym, aby uniknąć tej sytuacji, powinieneś starać się być tak precyzyjny, jak to tylko możliwe, mówiąc Springowi, jakiego fasola potrzebujesz. Jeśli Spring przeszuka swój kontekst i nie znajdzie ani jednego komponentu bean, który spełnia nasze wymagania, również zgłosi wyjątek. Na koniec po prostu wyświetlamy nazwy naszych zwierząt, aby sprawdzić, czy naprawdę otrzymaliśmy potrzebne przedmioty. Ale jeśli teraz uruchomimy program, zobaczymy, że Wiosna jest nieszczęśliwa — nie może znaleźć zwierząt, których potrzebujemy w swoim kontekście. To dlatego, że nie stworzył tych ziaren. Jak powiedziałem wcześniej, kiedy Spring skanuje klasy, szuka własnych adnotacji Springa. A jeśli Spring nie znajdzie tych adnotacji, to nie t myśli, że te klasy odpowiadają komponentom bean, które musi utworzyć. Naprawienie tego wymaga po prostu dodania pliku@Componentadnotację przed każdą z naszych klas zwierząt.

@Component
public class Cat {
	private String name = "Oscar";
	...
}
Ale jest coś więcej. Jeśli musimy wyraźnie powiedzieć Springowi, że komponent bean dla tej klasy powinien mieć określoną nazwę, podajemy ją w nawiasach po adnotacji. Na przykład, aby powiedzieć Springowi, aby nadał nazwę „ parrot-polly” fasolce papugi, której użyjemy, aby umieścić tę papugę w mainmetodzie, powinniśmy zrobić coś takiego:

@Component("parrot-polly")
public class Parrot {
	private String name = "Polly";
	...
}
To jest cały sens automatycznej konfiguracji . Piszesz swoje zajęcia, oznaczasz je niezbędnymi adnotacjami i przekazujesz Springowi pakiet, który zawiera twoje zajęcia. To jest pakiet, przez który framework będzie przechodził, aby znaleźć adnotacje i utworzyć obiekty tych klas. Nawiasem mówiąc, Spring szuka nie tylko @Componentadnotacji, ale także wszystkich innych adnotacji, które dziedziczą tę adnotację. Na przykład , @Controller, @RestController, @Servicei @Repositorywięcej, które przedstawimy w przyszłych artykułach. Teraz spróbujemy zrobić to samo, używając konfiguracji opartej na Javie . Aby rozpocząć, usuń plik@Componentnotatki z naszych zajęć. Aby było trudniej, wyobraź sobie, że to nie my napisaliśmy te klasy, więc nie możemy ich łatwo modyfikować, co oznacza, że ​​nie możemy dodawać adnotacji. To tak, jakby te klasy były spakowane w jakiejś bibliotece. W takim przypadku nie mamy możliwości edytowania tych klas, aby zostały rozpoznane przez Spring. Ale potrzebujemy obiektów tych klas! Tutaj potrzebujemy konfiguracji opartej na Javie, aby utworzyć obiekty. Aby rozpocząć, utwórz pakiet o nazwie takiej jak configs. W tym pakiecie utwórz zwykłą klasę Java, coś w rodzaju MyConfig, i oznacz ją adnotacją @Configuration.

@Configuration
public class MyConfig {
}
Teraz musimy ulepszyć main()metodę, zmieniając sposób tworzenia kontekstu. Możemy albo jawnie wskazać, która klasa ma naszą konfigurację:

ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class);
Jeśli mamy kilka różnych klas tworzących fasolę i chcemy połączyć kilka z nich jednocześnie, po prostu wskazujemy je tam wszystkie, oddzielając je przecinkami:

ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class, MyAnotherConfig.class);
A jeśli mamy ich za dużo i chcemy połączyć je wszystkie jednocześnie, to po prostu wskazujemy nazwę paczki, w której się znajdują:

ApplicationContext context =
	new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.configs");
W takim przypadku Spring przejrzy pakiet i znajdzie wszystkie klasy oznaczone adnotacją @Configuration. Cóż, a jeśli mamy naprawdę duży program, w którym konfiguracje są podzielone na różne pakiety, po prostu wskazujemy oddzieloną przecinkami listę nazw pakietów zawierających konfiguracje:

ApplicationContext context =
	new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.database.configs",
		"en.codegym.info.fatfaggy.animals.root.configs",
		"en.codegym.info.fatfaggy.animals.web.configs");
Lub nazwa pakietu, która jest wspólna dla nich wszystkich:

ApplicationContext context =
	new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals");
Możesz to zrobić, jak chcesz, ale wydaje mi się, że pierwsza opcja, która po prostu wskazuje klasę z konfiguracjami, będzie najlepiej pasować do naszego programu. Tworząc kontekst, Spring szuka klas oznaczonych adnotacją @Configurationi tworzy własne obiekty z tych klas. Próbuje wywołać metody oznaczone adnotacją @Bean, co oznacza, że ​​te metody zwracają komponenty bean (obiekty), które Spring doda do kontekstu. A teraz stworzymy fasolę dla kota, psa i papugi w naszej klasie z konfiguracją opartą na Javie. Jest to całkiem proste:

@Bean
public Cat getCat() {
	return new Cat();
}
Tutaj ręcznie tworzymy naszego kota i przekazujemy go Springowi, który następnie przechowuje nasz obiekt w swoim kontekście. Ponieważ nie nadaliśmy jawnie nazwy naszemu komponentowi bean, Spring nada mu taką samą nazwę, jak nazwa metody. W naszym przypadku kocia fasola będzie się nazywać „ getCat”. Ale ponieważ używamy klasy, a nie nazwy, aby uzyskać fasolę kota w metodzie main, nazwa fasoli nie jest dla nas ważna. Podobnie utwórz fasolę dla psów, pamiętając, że Spring nada fasoli nazwę metody. Aby wyraźnie nazwać naszą fasolkę papugową, po prostu podajemy jej nazwę w nawiasach po adnotacji @Bean:

@Bean("parrot-polly")
public Object weNeedMoreParrots() {
	return new Parrot();
}
Jak widać, tutaj wskazałem Objecttyp zwrotu i nadałem metodzie dowolną nazwę. Nie ma to wpływu na nazwę komponentu bean, ponieważ jawnie określiliśmy tutaj nazwę. Mimo to lepiej jest wskazać mniej lub bardziej znaczącą wartość zwracaną i nazwę metody. Zrób to choćby z innego powodu niż wyświadczenie sobie przysługi, kiedy ponownie otworzysz projekt za rok. :) Rozważmy teraz sytuację, w której potrzebujemy jednego komponentu bean, aby utworzyć inny komponent bean . Załóżmy na przykład, że chcemy, aby imię kota w kociej fasoli było imieniem papugi plus ciąg „-killer”. Bez problemu!

@Bean
public Cat getCat(Parrot parrot) {
	Cat cat = new Cat();
	cat.setName(parrot.getName() + "-killer");
	return cat;
}
Tutaj Spring zobaczy, że aby stworzyć tę fasolę, framework musi przejść do wcześniej utworzonej fasoli papugi. W związku z tym zorganizuje niezbędny łańcuch wywołań metod: najpierw wywoływana jest metoda tworzenia papugi, a następnie framework przekazuje nową papugę do metody tworzenia kotów. Oto, gdzie wchodzi w grę wstrzykiwanie zależności : sam Spring przekazuje wymaganą papugę fasoli do naszej metody. Jeśli IDEA zdenerwuje się z powodu parrotzmiennej, nie zapomnij zmienić typu zwracanego metody tworzenia papug z Objectna Parrot. Ponadto konfiguracja oparta na Javie pozwala na uruchomienie absolutnie dowolnego kodu Javaw twoich metodach tworzenia fasoli. Można zrobić naprawdę wszystko: tworzyć inne obiekty pomocnicze, wywoływać dowolne inne metody, nawet te nieoznaczone adnotacjami Springa, tworzyć pętle, warunki boolowskie — cokolwiek przyjdzie nam do głowy! Nie wszystko to jest możliwe przy automatycznej konfiguracji, a tym bardziej przy konfiguracji XML. Rozważmy teraz problem, który jest nieco zabawniejszy. Polimorfizm i interfejsy :) Stworzymy WeekDayinterfejs i stworzymy 7 klas implementujących ten interfejs: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday. Nadamy interfejsowi String getWeekDayName()metodę, która zwróci nazwę dnia tygodnia dla odpowiedniej klasy. Innymi słowy, Mondayklasa powróci”Monday” itd. Załóżmy, że po uruchomieniu aplikacji naszym zadaniem jest umieszczenie w kontekście komponentu bean odpowiadającego bieżącemu dniu tygodnia. Nie dla wszystkich klas implementujących interfejs — tylko dla jednego komponentu bean, który jest nam potrzebny. WeekDayMożesz zrób to 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 zwracanym typem jest nasz interfejs. Metoda zwraca bona fide obiekt jednej z klas implementujących interfejs, w zależności od bieżącego dnia tygodnia. Teraz możemy wykonać następujące czynności w main()metodzie:

WeekDay weekDay = context.getBean(WeekDay.class);
System.out.println("Today is " + weekDay.getWeekDayName() + "!");
U mnie program mówi mi, że jest niedziela :) Jestem przekonany, że jeśli jutro uruchomię program, kontekst będzie zawierał zupełnie inny obiekt. Zauważ, że pobieramy komponent bean po prostu za pomocą interfejsu: context.getBean(WeekDay.class). Spring wyszuka w swoim kontekście komponent bean, który implementuje interfejs, i zwróci go. Następnie okazuje się, że nasza WeekDayzmienna kończy się obiektem Sunday, a podczas pracy z tą zmienną obowiązuje znana koncepcja polimorfizmu. :) A teraz kilka słów o podejściu łączonym , w którym część beanów jest tworzona automatycznie przez Springa, część przez skanowanie pakietów w poszukiwaniu klas z adnotacją @Component, a jeszcze inne przez konfigurację opartą na Javie. Rozważając to, powrócimy do oryginalnej wersji, w której Cat, Dog, iParrotklasy zostały oznaczone adnotacją @Component. Załóżmy, że chcemy utworzyć fasolę dla naszych zwierząt, tak aby Spring automatycznie zeskanował paczkę entities, ale chcemy też utworzyć fasolkę z dniem tygodnia, tak jak właśnie to zrobiliśmy. Wystarczy dodać @ComponentScanadnotację na poziomie klasy MyConfig, którą wskazujemy przy tworzeniu kontekstu w main(), oraz wskazać w nawiasach paczkę, którą należy przeskanować i automatycznie utworzyć komponenty niezbędnej klasy:

@Configuration
@ComponentScan("en.codegym.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();
		}
	}
}
Podczas tworzenia kontekstu Spring widzi, że musi przetworzyć MyConfigklasę. Wchodzi do klasy i widzi, że musi przeskanować en.codegym.info.fatfaggy.animals.entitiespakiet „ ” i utworzyć komponent bean tych klas, po czym wykonuje metodę MyConfigklasy getDay()i dodaje komponent WeekDaybean do kontekstu. W main()metodzie mamy teraz dostęp do wszystkich potrzebnych nam fasoli: zarówno obiektów zwierzęcych, jak i fasoli z dniem tygodnia. Jeśli kiedykolwiek będziesz musiał zmusić Springa do pobierania plików konfiguracyjnych XML, możesz przeprowadzić własne wyszukiwanie w Internecie, aby znaleźć wyjaśnienie :) Podsumowanie:
  • Spróbuj użyć automatycznej konfiguracji
  • Podczas automatycznej konfiguracji należy wskazać nazwę pakietu zawierającego klasy, których komponenty bean mają zostać utworzone
  • Klasy te są oznaczone @Componentadnotacją
  • Spring przebiega przez wszystkie te klasy, tworzy obiekty i umieszcza je w kontekście;
  • Jeśli automatyczna konfiguracja z jakiegoś powodu nam nie odpowiada, używamy konfiguracji opartej na Javie
  • W tym przypadku tworzymy zwykłą klasę Java, której metody zwracają potrzebne nam obiekty. Zaznaczamy tę klasę adnotacją @Configuration, jeśli mamy zamiar przeskanować cały pakiet zamiast wskazywać konkretną klasę z konfiguracją podczas tworzenia kontekstu
  • Metody tej klasy, które zwracają komponent bean, są oznaczone @Beanadnotacją
  • Jeśli chcemy włączyć automatyczne skanowanie podczas korzystania z konfiguracji opartej na Javie, używamy adnotacji @ComponentScan.
Jeśli ten artykuł był całkowicie zagmatwany, spróbuj przeczytać go za kilka dni. Lub jeśli jesteś na jednym z wczesnych poziomów CodeGym, może być trochę za wcześnie na naukę Springa. Zawsze możesz wrócić do tego artykułu nieco później, gdy poczujesz się pewniej w swoich umiejętnościach programowania w języku Java. Jeśli wszystko jest jasne, możesz spróbować przekonwertować swój ulubiony projekt na Wiosnę :) Jeśli niektóre rzeczy są jasne, a inne nie, to proszę zostaw komentarz :) Daj mi znać o swoich sugestiach i krytyce, jeśli poszedłem źle gdzieś lub napisał jakiś nonsens :) W następnym artykule nagle zanurzymy 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