CodeGym /Java blog /Tilfældig /Forår for dovne mennesker Fundament, grundlæggende begreb...
John Squirrels
Niveau
San Francisco

Forår for dovne mennesker Fundament, grundlæggende begreber og eksempler med kode. Del 2

Udgivet i gruppen
I den forrige artikel forklarede jeg kort, hvad forår er, og hvad bønner og kontekst er. Nu er det tid til at prøve det. Jeg vil gøre det ved hjælp af IntelliJ IDEA Enterprise Edition. Men alle mine eksempler burde også fungere i den gratis IntelliJ IDEA Community Edition. I skærmbillederne, hvis du ser, at jeg har et vindue, som du ikke har, skal du ikke bekymre dig - det er ikke vigtigt for dette projekt :) Forår for dovne mennesker Fundament, grundlæggende begreber og eksempler med kode.  Del 2 - 1Først skal du oprette et tomt Maven-projekt. Jeg viste hvordan man gør dette i artiklen på dette link . Læs op til ordene " Det er på tide, at vi konverterer vores Maven-projekt til et webprojekt. " - derefter viser artiklen, hvordan man laver et webprojekt, men det har vi ikke brug for lige nu. I src/main/javamappe, opret en pakke (i mit tilfælde kaldte jeg den " en.codegym.info.fatfaggy.animals. Du kan kalde den hvad du vil. Bare glem ikke at erstatte mit pakkenavn med dit pakkenavn alle de rigtige steder. Opret nu klassen Mainog tilføj en metode

public static void main(String[] args) {
    ...
}
Åbn derefter filen pom.xml og tilføj sektionen dependencies. Gå nu til Maven-depotet og find forårskonteksten for den seneste stabile version. Læg det vi finder ind i dependenciesafsnittet. Jeg beskrev denne proces mere detaljeret i denne anden CodeGym-artikel (se afsnittet med titlen " Forbindelse af afhængigheder i Maven "). Så vil Maven selv finde og downloade de nødvendige afhængigheder. I sidste ende skulle du få noget som dette: Forår for dovne mennesker Fundament, grundlæggende begreber og eksempler med kode.  Del 2 - 2I vinduet til venstre kan du se projektstrukturen med pakken og klassen Main. Det midterste vindue viser, hvordan pom.xml ser ud for mig. Jeg har også tilføjet en egenskabafsnit til det. Dette afsnit fortæller Maven, hvilken version af Java jeg bruger i mine kildefiler, og hvilken version der skal kompileres. Dette er bare for at IDEA ikke advarer mig om, at jeg bruger en gammel version af Java. Dette er valgfrit :) Det højre vindue gør det klart, at selvom vi kun tilsluttede fjeder-kontekst-modulet, trak det automatisk fjederkerne, fjeder-bønner, spring-aop og fjeder-udtryk modulerne ind. Vi kunne have tilsluttet hvert modul separat ved at skrive en afhængighed for hvert modul med den eksplicitte version i pom.xml-filen, men indtil videre er vi tilfredse med tingene, som de er. Opret nu entitiespakken og opret 3 klasser i den: Cat, Dog, Parrot. Lad os give hvert dyr et navn (private String name- du kan hardkode nogle værdier der). Getterne/sætterne er offentlige. Nu går vi videre til Mainklassen og main()metoden, og vi skriver noget som dette:

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());
}
Først opretter vi et kontekstobjekt, der fortæller konstruktøren, hvilken pakke han skal kigge i for at finde bønner. Med andre ord vil Spring gennemgå denne pakke og forsøge at finde klasser markeret med særlige anmærkninger, der angiver, at de er bønner. Derefter opretter den objekterne i disse klasser og sætter dem i konteksten. Herefter får vi en kat fra denne sammenhæng. Vi opfordrer kontekstobjektet til at give os en bønne (objekt), der angiver klassen for det objekt, vi ønsker (i øvrigt kan vi også angive grænseflader, ikke kun klasser). Derefter returnerer Spring et objekt af den anmodede klasse, som vi så gemmer i en variabel. Dernæst beder vi Spring om at få os en bønne kaldet "hund". Når foråret skaber enDogobjekt, giver det objektet et standardnavn (medmindre den oprettede bønne eksplicit er blevet tildelt et navn), som er klassens navn, men med et indledende lille bogstav. I dette tilfælde hedder vores klasse Dog, så bønnens navn er være "hund". Hvis vi havde brug for et BufferedReaderobjekt der, ville Spring kalde det "bufferedReader". Og fordi Java ikke kan være 100% sikker på hvilken klasse vi ønsker, returnerer den et Objectobjekt, som vi så manuelt caster til den ønskede type, dvs.Dog. Muligheden, hvor klassen er angivet eksplicit, er mere praktisk. Den tredje mulighed er at få en bønne efter klassenavn og efter bønnenavn. Det er muligt, at konteksten kan have flere bønner af en enkelt klasse. For at angive den særlige bønne, vi har brug for, angiver vi dens navn. Fordi vi også udtrykkeligt angiver klassen her, skal vi ikke længere udføre en cast. VIGTIG!Hvis Spring finder flere bønner, der matcher vores krav, så kan den ikke bestemme, hvilken bønne vi skal give os, så det giver en undtagelse. For at undgå denne situation bør du derfor prøve at være så specifik som muligt med at fortælle Spring, hvilken bønne du har brug for. Hvis Spring søger sin kontekst og ikke finder en enkelt bønne, der matcher vores krav, så vil det også give en undtagelse. Til sidst viser vi blot navnene på vores dyr for at bekræfte, at vi virkelig har fået de genstande, vi har brug for. Men hvis vi kører programmet nu, vil vi se, at foråret er ulykkeligt - det kan ikke finde de dyr, vi har brug for i sin sammenhæng. Dette er fordi det ikke har skabt disse bønner. Som jeg sagde tidligere, når Spring scanner klasser, leder den efter sine egne Spring-annotationer. Og hvis foråret ikke finder disse anmærkninger, så gør det ikke Jeg tror ikke, at disse klasser svarer til bønner, som den skal lave. At rette dette kræver blot tilføjelse af@Componentanmærkning foran hver af vores dyreklasser.

@Component
public class Cat {
	private String name = "Oscar";
	...
}
Men der er mere. Hvis vi eksplicit skal fortælle Spring, at bønnen til denne klasse skal have et bestemt navn, angiver vi navnet i parentes efter annotationen. For for eksempel at bede Spring give navnet " parrot-polly" til papegøjebønnen, som er det navn, vi vil bruge til at få denne papegøje med i metoden main, bør vi gøre noget som dette:

@Component("parrot-polly")
public class Parrot {
	private String name = "Polly";
	...
}
Dette er hele pointen med automatisk konfiguration . Du skriver dine klasser, markerer dem med de nødvendige anmærkninger og fortæller Spring pakken, der har dine klasser. Dette er pakken, som rammerne vil løbe igennem for at finde annoteringer og skabe objekter af disse klasser. Spring leder i øvrigt ikke kun efter @Componentannoteringer, men også alle andre annoteringer, der arver denne. For eksempel, @Controller, , , og mere, som vi vil introducere i fremtidige artikler @RestController. Nu vil vi prøve at gøre det samme ved hjælp af Java-baseret konfiguration . For at komme i gang skal du fjerne@Service@Repository@Componentkommentarer fra vores klasser. For at gøre tingene mere udfordrende, forestil dig, at vi ikke har skrevet disse klasser, så vi kan ikke nemt ændre dem, hvilket betyder, at vi ikke kan tilføje annoteringer. Det er som om disse klasser er pakket i et eller andet bibliotek. I dette tilfælde er der ingen måde for os at redigere disse klasser, så de genkendes af Spring. Men vi har brug for genstande af disse klasser! Her har vi brug for Java-baseret konfiguration for at skabe objekterne. For at komme i gang skal du oprette en pakke med et navn som configs. I denne pakke skal du oprette en almindelig Java-klasse, noget i stil med MyConfig, og markere den med @Configurationannotationen.

@Configuration
public class MyConfig {
}
Nu skal vi justere main()metoden og ændre, hvordan vi skaber konteksten. Vi kan enten udtrykkeligt angive, hvilken klasse der har vores konfiguration:

ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class);
Hvis vi har flere forskellige klasser, der skaber bønner, og vi ønsker at forbinde flere af dem samtidigt, angiver vi dem alle der, adskilt med kommaer:

ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class, MyAnotherConfig.class);
Og hvis vi har for mange af dem, og vi vil forbinde dem alle samtidigt, angiver vi blot navnet på den pakke, de er indeholdt i:

ApplicationContext context =
	new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.configs");
I dette tilfælde vil Spring gennemgå pakken og finde alle de klasser, der er markeret med anmærkningen @Configuration. Nå, og hvis vi har et rigtig stort program, hvor konfigurationerne er opdelt i forskellige pakker, så angiver vi blot en kommasepareret liste med navne på de pakker, der indeholder konfigurationerne:

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");
Eller navnet på en pakke, der er fælles for dem alle:

ApplicationContext context =
	new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals");
Du kan gøre det, som du vil, men det forekommer mig, at den allerførste mulighed, som blot angiver en klasse med konfigurationerne, vil passe bedst til vores program. Når du opretter en kontekst, leder Spring efter klasser, der er markeret med annoteringen, @Configurationog vil oprette sine egne objekter af disse klasser. Den forsøger at kalde metoder, der er markeret med @Beanannoteringen, hvilket betyder, at disse metoder returnerer bønner (objekter), som Spring vil tilføje til konteksten. Og nu vil vi skabe bønner til en kat, hund og papegøje i vores klasse med Java-baseret konfiguration. Dette er ret simpelt at gøre:

@Bean
public Cat getCat() {
	return new Cat();
}
Her skaber vi manuelt vores kat og afleverer den til Spring, som så holder vores objekt i sin kontekst. Da vi ikke eksplicit gav et navn til vores bønne, vil Spring give den samme navn som metodens navn. I vores tilfælde vil kattebønnen blive kaldt " getCat". Men fordi vi bruger klassen, ikke navnet, til at få kattebønnen med i metoden main, er bønnens navn ikke vigtigt for os. På samme måde skal du lave en hundebønne, mens du husker på, at Spring vil give metodenavnet til bønnen. For eksplicit at navngive vores papegøjebønne, angiver vi blot dens navn i parentes efter annotationen @Bean:

@Bean("parrot-polly")
public Object weNeedMoreParrots() {
	return new Parrot();
}
Som du kan se, angav jeg her en Objectreturtype og gav metoden et vilkårligt navn. Dette påvirker ikke bønnens navn, fordi vi udtrykkeligt har angivet navnet her. Alligevel er det bedre at angive en mere eller mindre meningsfuld returværdi og metodenavn. Gør dette om ikke andet for at gøre dig selv en tjeneste, når du genåbner projektet om et år. :) Overvej nu situationen, hvor vi har brug for en bønne for at skabe en anden bønne . Antag for eksempel, at vi ønsker, at navnet på katten i kattebønnen skal være papegøjens navn plus strengen "-killer". Intet problem!

@Bean
public Cat getCat(Parrot parrot) {
	Cat cat = new Cat();
	cat.setName(parrot.getName() + "-killer");
	return cat;
}
Her vil foråret se, at for at skabe denne bønne skal rammen passere i den tidligere oprettede papegøjebønne. I overensstemmelse hermed vil den arrangere den nødvendige kæde af metodekald: først kaldes den papegøje-skabende metode, og derefter overfører rammen den nye papegøje til den kat-skabende metode. Her er hvor afhængighedsinjektion kommer ind i billedet: Foråret sender selv den nødvendige papegøjebønne til vores metode. Hvis IDEA bliver ked af parrotvariablen, så glem ikke at ændre den papegøjeskabende metodes returtype fra Objecttil Parrot. Derudover giver Java-baseret konfiguration dig mulighed for at køre absolut enhver Java-kodei dine bønne-skabende metoder. Du kan virkelig gøre hvad som helst: oprette andre hjælpeobjekter, kalde andre metoder, selv dem, der ikke er markeret med forårsannoteringer, skabe sløjfer, booleske forhold - uanset hvad du tænker på! Dette er ikke alt muligt med automatisk konfiguration, og endnu mindre med XML-konfiguration. Lad os nu overveje et problem, der er lidt sjovere. Polymorfi og grænseflader :) Vi opretter en WeekDaygrænseflade og skaber 7 klasser, der implementerer denne grænseflade: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday. Vi giver grænsefladen en String getWeekDayName()metode, som returnerer navnet på ugedagen for den tilsvarende klasse. Med andre ord Mondayvender klassen tilbage "Monday", osv. Ved start af applikationen, antag, at vores opgave er at sætte en bean svarende til den aktuelle ugedag ind i konteksten. Ikke bønner for alle klasser, der implementerer grænsefladen - kun den ene bean, som vi har brug for. Du WeekDaykan gør det sådan her:

@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();
	}
}
Her er returtypen vores grænseflade. Metoden returnerer et bona fide-objekt fra en af ​​de klasser, der implementerer grænsefladen, afhængigt af den aktuelle ugedag. Nu kan vi gøre følgende i main()metoden:

WeekDay weekDay = context.getBean(WeekDay.class);
System.out.println("Today is " + weekDay.getWeekDayName() + "!");
For mig fortæller programmet mig, at det er søndag :) Jeg er overbevist om, at hvis jeg kører programmet i morgen, vil konteksten indeholde et helt andet objekt. Bemærk, at vi får bønnen blot ved at bruge grænsefladen: context.getBean(WeekDay.class). Spring vil søge sin kontekst efter bønnen, der implementerer grænsefladen, og vil returnere den. Så viser det sig, at vores WeekDayvariabel ender med et søndagsobjekt, og det velkendte begreb polymorfi gælder, når vi arbejder med denne variabel. :) Nu et par ord om den kombinerede tilgang , hvor nogle bønner oprettes automatisk af Spring, nogle ved at scanne pakker for klasser med annoteringen @Component, og andre af Java-baseret konfiguration. Mens vi overvejer dette, vender vi tilbage til den originale version, hvor Cat, Dog, ogParrotklasser blev markeret med @Componentanmærkningen. Antag, at vi vil skabe bønner til vores dyr ved at lade Spring automatisk scanne pakken entities, men vi vil også gerne lave en bønne med ugedagen, som vi lige har gjort. Alt du skal gøre er at tilføje @ComponentScanannoteringen på klasseniveau MyConfig, som vi angiver, når du opretter konteksten i main(), og angive i parentes den pakke, der skal scannes og oprette bønner af de nødvendige klasser automatisk:

@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();
		}
	}
}
Når man skaber konteksten, ser Spring, at den skal bearbejde klassen MyConfig. Den går ind i klassen og ser, at den skal scanne " en.codegym.info.fatfaggy.animals.entities"-pakken og oprette bønner af disse klasser, hvorefter den udfører MyConfigklassens getDay()metode og tilføjer en WeekDaybean til konteksten. I main()metoden har vi nu adgang til alle de bønner, vi skal bruge: både dyregenstande og en bønne med ugedag. Hvis du nogensinde har brug for at få Spring til også at hente nogle XML-konfigurationsfiler, kan du lave din egen websøgning for at finde en forklaring :) Resumé:
  • Prøv at bruge automatisk konfiguration
  • Under automatisk konfiguration skal du angive navnet på den pakke, der indeholder de klasser, hvis bønner skal oprettes
  • Disse klasser er markeret med @Componentanmærkningen
  • Foråret løber gennem alle disse klasser, skaber objekter og sætter dem i konteksten;
  • Hvis automatisk konfiguration af en eller anden grund ikke passer os, bruger vi Java-baseret konfiguration
  • I dette tilfælde opretter vi en almindelig Java-klasse, hvis metoder returnerer de objekter, vi har brug for. Vi markerer denne klasse med @Configurationannotationen, hvis vi skal scanne hele pakken i stedet for at angive en specifik klasse med konfigurationen, når vi opretter konteksten
  • Metoderne i denne klasse, der returnerer bønner, er markeret med @Beananmærkningen
  • Hvis vi ønsker at aktivere automatisk scanning ved brug af Java-baseret konfiguration, bruger vi annotationen @ComponentScan.
Hvis denne artikel har været fuldstændig forvirrende, så prøv at læse den om et par dage. Eller hvis du er på et af de tidlige niveauer i CodeGym, kan det være lidt tidligt for dig at læse Spring. Du kan altid vende tilbage til denne artikel lidt senere, når du føler dig mere sikker på dine Java-programmeringsfærdigheder. Hvis alt er klart, så kan du prøve at konvertere et eller andet kæledyrsprojekt til Spring :) Hvis nogle ting er klare, men andre ting ikke er, så smid en kommentar :) Fortæl mig dine forslag og kritik, hvis jeg gik galt et eller andet sted eller skrev noget sludder :) I den næste artikel dykker vi brat ned i spring-web-mvc og laver en simpel webapplikation ved hjælp af Spring.
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION