CodeGym /Java blogg /Slumpmässig /Vår för lata människor Foundation, grundläggande begrepp ...
John Squirrels
Nivå
San Francisco

Vår för lata människor Foundation, grundläggande begrepp och exempel med kod. Del 2

Publicerad i gruppen
I förra artikeln förklarade jag kort vad våren är och vad bönor och sammanhang är. Nu är det dags att prova. Jag ska göra det med IntelliJ IDEA Enterprise Edition. Men alla mina exempel borde också fungera i den kostnadsfria IntelliJ IDEA Community Edition. I skärmdumparna, om du ser att jag har ett fönster som du inte har, oroa dig inte — det är inte viktigt för det här projektet :) Vår för lata människor Foundation, grundläggande begrepp och exempel med kod.  Del 2 - 1Skapa först ett tomt Maven-projekt. Jag visade hur man gör detta i artikeln på denna länk . Läs upp till orden " Det är dags för oss att konvertera vårt Maven-projekt till ett webbprojekt. " — efter det visar artikeln hur man gör ett webbprojekt, men det behöver vi inte just nu. I src/main/javamapp, skapa ett paket (i mitt fall kallade jag det " . en.codegym.info.fatfaggy.animalsDu kan kalla det vad du vill. Glöm bara inte att byta ut mitt paketnamn med ditt paketnamn på alla rätt ställen. Skapa nu klassen Mainoch lägg till en metod

public static void main(String[] args) {
    ...
}
Öppna sedan filen pom.xml och lägg till avsnittet dependencies. Gå nu till Maven-förvaret och hitta vårkontexten för den senaste stabila versionen. Lägg in det vi hittar i avsnittet dependencies. Jag beskrev den här processen mer detaljerat i denna andra CodeGym-artikel (se avsnittet " Ansluta beroenden i Maven "). Sedan kommer Maven själv att hitta och ladda ner nödvändiga beroenden. I slutändan bör du få något sånt här: Vår för lata människor Foundation, grundläggande begrepp och exempel med kod.  Del 2 - 2I fönstret till vänster kan du se projektstrukturen med paketet och klassen Main. Mittfönstret visar hur pom.xml ser ut för mig. Jag har också lagt till en egenskaperavsnitt till den. Det här avsnittet berättar för Maven vilken version av Java jag använder i mina källfiler och vilken version som ska kompileras. Detta är bara för att IDEA inte ska varna mig för att jag använder en gammal version av Java. Detta är valfritt :) Det högra fönstret gör det tydligt att även om vi bara kopplade in fjäderkontextmodulen drog den automatiskt in fjäderkärna, fjäderbönor, fjäder-aop och fjäderuttrycksmoduler. Vi kunde ha kopplat varje modul separat och skrivit ut ett beroende för varje modul med den explicita versionen i filen pom.xml, men för närvarande är vi nöjda med saker och ting som de är. Skapa nu entitiespaketet och skapa 3 klasser i det: Cat, Dog, Parrot. Låt oss ge varje djur ett namn (private String name— du kan hårdkoda vissa värden där). Gettarna/sättarna är offentliga. Nu går vi vidare till Mainklassen och main()metoden, och vi skriver ungefär så här:

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 skapar vi ett kontextobjekt som talar om för konstruktören vilket paket som ska titta i för att hitta bönor. Med andra ord kommer Spring att gå igenom det här paketet och försöka hitta klasser märkta med speciella anteckningar som indikerar att de är bönor. Sedan skapar den objekten för dessa klasser och sätter dem i sammanhanget. Efter det får vi en katt från det här sammanhanget. Vi uppmanar kontextobjektet att ge oss en böna (objekt), som indikerar klassen för objektet vi vill ha (förresten, vi kan också ange gränssnitt, inte bara klasser). Efter det returnerar Spring ett objekt av den begärda klassen, som vi sedan sparar i en variabel. Därefter ber vi Spring att skaffa oss en böna som heter "hund". När våren skapar enDogobjekt, ger det objektet ett standardnamn (såvida den skapade bönan inte uttryckligen har tilldelats ett namn), vilket är klassnamnet men med en initial liten bokstav. I det här fallet heter vår klass Dog, så bönans namn är vara "hund". Om vi ​​behövde ett BufferedReaderobjekt där, då skulle Spring döpa det till "bufferedReader". Och eftersom Java inte kan vara 100% säker på vilken klass vi vill ha så returnerar den ett Objectobjekt som vi sedan manuellt castar till önskad typ, dvs.Dog. Alternativet där klassen anges explicit är bekvämare. Det tredje alternativet är att få en böna efter klassnamn och efter bönnamn. Det är möjligt att sammanhanget kan ha flera bönor av en enda klass. För att ange vilken böna vi behöver anger vi dess namn. Eftersom vi också uttryckligen anger klassen här, behöver vi inte längre utföra en cast. VIKTIG!Om Spring hittar flera bönor som matchar våra krav, så kan den inte avgöra vilken böna vi ska ge oss, så det blir ett undantag. För att undvika denna situation bör du därför försöka vara så specifik som möjligt när du talar om för Spring vilken böna du behöver. Om Spring söker igenom sitt sammanhang och inte lyckas hitta en enda böna som matchar våra krav, kommer det också att skapa ett undantag. Slutligen visar vi helt enkelt namnen på våra djur för att verifiera att vi verkligen har de föremål vi behöver. Men om vi kör programmet nu kommer vi att se att våren är olycklig — den kan inte hitta de djur vi behöver i sitt sammanhang. Detta beror på att det inte har skapat dessa bönor. Som jag sa tidigare, när Spring skannar klasser, letar den efter sina egna Spring-kommentarer. Och om våren inte hittar dessa kommentarer, så gör den inte Jag tror inte att dessa klasser motsvarar bönor som den behöver skapa. Att fixa detta kräver helt enkelt att lägga till@Componentanteckning framför var och en av våra djurklasser.

@Component
public class Cat {
	private String name = "Oscar";
	...
}
Men det finns mer. Om vi ​​uttryckligen behöver tala om för Spring att bönan för denna klass ska ha ett specifikt namn, anger vi namnet inom parentes efter anteckningen. För att till exempel säga till Spring att ge namnet " parrot-polly" till papegojbönan, vilket är det namn vi kommer att använda för att få in denna papegoja i metoden, mainbör vi göra något så här:

@Component("parrot-polly")
public class Parrot {
	private String name = "Polly";
	...
}
Detta är hela poängen med automatisk konfiguration . Du skriver dina klasser, markerar dem med nödvändiga anteckningar och berättar för Spring paketet som innehåller dina klasser. Detta är paketet som ramverket kommer att köras igenom för att hitta kommentarer och skapa objekt av dessa klasser. Spring letar förresten inte bara efter @Componentannoteringar, utan även alla andra annoteringar som ärver denna. Till exempel , @Controller, @RestController, @Service, @Repositoryoch mer, som vi kommer att introducera i framtida artiklar. Nu ska vi försöka göra samma sak med Java-baserad konfiguration . För att komma igång, ta bort@Componentkommentarer från våra klasser. För att göra saker mer utmanande, föreställ dig att vi inte skrev dessa klasser, så vi kan inte enkelt ändra dem, vilket innebär att vi inte kan lägga till kommentarer. Det är som att dessa klasser är paketerade i något bibliotek. I det här fallet finns det inget sätt för oss att redigera dessa klasser så att de känns igen av Spring. Men vi behöver objekt av dessa klasser! Här behöver vi Java-baserad konfiguration för att skapa objekten. För att komma igång, skapa ett paket med ett namn som configs. I det här paketet skapar du en vanlig Java-klass, något som , MyConfigoch markerar den med @Configurationanteckningen.

@Configuration
public class MyConfig {
}
Nu måste vi justera main()metoden, ändra hur vi skapar sammanhanget. Vi kan antingen uttryckligen ange vilken klass som har vår konfiguration:

ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class);
Om vi ​​har flera olika klasser som skapar bönor och vi vill koppla ihop flera av dem samtidigt, anger vi dem alla där, separerade med kommatecken:

ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class, MyAnotherConfig.class);
Och om vi har för många av dem och vi vill ansluta dem alla samtidigt, anger vi helt enkelt namnet på paketet de ingår i:

ApplicationContext context =
	new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.configs");
I det här fallet kommer Spring att gå igenom paketet och hitta alla klasser som är markerade med anteckningen @Configuration. Tja, och om vi har ett riktigt stort program där konfigurationerna är uppdelade i olika paket, så anger vi helt enkelt en kommaavgränsad lista med namn på paketen som innehåller konfigurationerna:

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 namnet på ett paket som är gemensamt för dem alla:

ApplicationContext context =
	new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals");
Du kan göra det hur du vill, men det verkar för mig att det allra första alternativet, som helt enkelt indikerar en klass med konfigurationerna, kommer att passa vårt program bäst. När du skapar ett sammanhang letar Spring efter klasser markerade med anteckningen @Configurationoch kommer att skapa sina egna objekt för dessa klasser. Den försöker kalla metoder markerade med anteckningen @Bean, vilket innebär att dessa metoder returnerar bönor (objekt) som Spring kommer att lägga till i sammanhanget. Och nu ska vi skapa bönor för en katt, hund och papegoja i vår klass med Java-baserad konfiguration. Detta är ganska enkelt att göra:

@Bean
public Cat getCat() {
	return new Cat();
}
Här skapar vi manuellt vår katt och lämnar den till Spring, som sedan håller vårt föremål i sitt sammanhang. Eftersom vi inte uttryckligen gav ett namn till vår böna kommer Spring att ge den samma namn som metoden. I vårt fall kommer kattbönan att kallas " " getCat. Men eftersom vi använder klassen, inte namnet, för att få in kattbönan i metoden, mainär bönans namn inte viktigt för oss. Skapa på samma sätt en hundböna, med tanke på att Spring kommer att ge metoden namn till bönan. För att uttryckligen namnge vår papegojböna, anger vi helt enkelt dess namn inom parentes efter anteckningen @Bean:

@Bean("parrot-polly")
public Object weNeedMoreParrots() {
	return new Parrot();
}
Som du kan se angav jag här en Objectreturtyp och gav metoden ett godtyckligt namn. Detta påverkar inte bönans namn, eftersom vi uttryckligen angav namnet här. Ändå är det bättre att ange ett mer eller mindre meningsfullt returvärde och metodnamn. Gör detta om inte av någon annan anledning än att göra dig själv en tjänst när du öppnar projektet igen om ett år. :) Tänk nu på situationen där vi behöver en böna för att skapa en annan böna . Anta till exempel att vi vill att namnet på katten i kattbönan ska vara papegojans namn plus strängen "-killer". Inga problem!

@Bean
public Cat getCat(Parrot parrot) {
	Cat cat = new Cat();
	cat.setName(parrot.getName() + "-killer");
	return cat;
}
Här kommer våren att se att för att skapa denna böna måste stommen passera in i den tidigare skapade papegojbönan. Följaktligen kommer den att ordna den nödvändiga kedjan av metodanrop: först anropas metoden för att skapa papegojor och sedan skickar ramverket den nya papegojan till metoden för att skapa katt. Här är där beroendeinjektion kommer in i bilden: Våren själv skickar den nödvändiga papegojbönan till vår metod. Om IDEA blir upprörd över parrotvariabeln, glöm inte att ändra den papegojskapande metodens returtyp från Objecttill Parrot. Dessutom låter Java-baserad konfiguration dig köra absolut vilken Java-kod som helsti dina metoder för att skapa bönor. Du kan verkligen göra vad som helst: skapa andra hjälpobjekt, anropa andra metoder, även de som inte är markerade med vårkommentarer, skapa loopar, booleska villkor - vad du än tänker på! Detta är inte allt möjligt med automatisk konfiguration, och ännu mindre med XML-konfiguration. Låt oss nu överväga ett problem som är lite roligare. Polymorfism och gränssnitt :) Vi skapar ett WeekDaygränssnitt och skapar 7 klasser som implementerar detta gränssnitt: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday. Vi kommer att ge gränssnittet en String getWeekDayName()metod som returnerar namnet på veckodagen för motsvarande klass. Med andra ord, Mondayklassen kommer tillbaka "Monday", etc. När du startar applikationen, anta att vår uppgift är att sätta en böna som motsvarar den aktuella veckodagen i sammanhanget. Inte bönor för alla klasser som implementerar gränssnittet - bara den ena bönan som vi behöver. Du WeekDaykan gör det ungefär så här:

@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();
	}
}
Här är returtypen vårt gränssnitt. Metoden returnerar ett bona fide-objekt av en av klasserna som implementerar gränssnittet, beroende på aktuell veckodag. Nu kan vi göra följande i main()metoden:

WeekDay weekDay = context.getBean(WeekDay.class);
System.out.println("Today is " + weekDay.getWeekDayName() + "!");
För mig säger programmet till mig att det är söndag :) Jag är övertygad om att om jag kör programmet imorgon kommer sammanhanget att innehålla ett helt annat objekt. Observera att vi får bönan helt enkelt genom att använda gränssnittet: context.getBean(WeekDay.class). Spring kommer att söka sitt sammanhang efter bönan som implementerar gränssnittet och kommer att returnera den. Sedan visar det sig att vår WeekDayvariabel hamnar på ett söndagsobjekt, och det välbekanta begreppet polymorfism gäller när vi arbetar med denna variabel. :) Nu några ord om det kombinerade tillvägagångssättet , där vissa bönor skapas automatiskt av Spring, vissa genom att skanna paket för klasser med anteckningen @Componentoch andra av Java-baserad konfiguration. När vi överväger detta återgår vi till den ursprungliga versionen, där , Cat, DogochParrotklasser markerades med @Componentanteckningen. Anta att vi vill skapa bönor för våra djur genom att låta Spring automatiskt skanna paketet entities, men vi vill också skapa en böna med veckodagen, som vi precis gjorde. Allt du behöver göra är att lägga till @ComponentScanannoteringen på klassnivå MyConfig, vilket vi anger när vi skapar sammanhanget i , main()och ange inom parentes paketet som behöver skannas och skapa bönor av de nödvändiga klasserna automatiskt:

@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 skapar sammanhanget ser Spring att den behöver bearbeta MyConfigklassen. Den går in i klassen och ser att den behöver skanna en.codegym.info.fatfaggy.animals.entitiespaketet " " och skapa bönor av dessa klasser, varefter den kör MyConfigklassens getDay()metod och lägger till en WeekDayböna i sammanhanget. I main()metoden har vi nu tillgång till alla bönor vi behöver: både djurföremål och en böna med veckodag. Om du någonsin behöver få Spring att också plocka upp några XML-konfigurationsfiler, kan du göra din egen webbsökning för att hitta en förklaring :) Sammanfattning:
  • Försök att använda automatisk konfiguration
  • Under automatisk konfiguration, ange namnet på paketet som innehåller de klasser vars bönor måste skapas
  • Dessa klasser är markerade med @Componentanteckningen
  • Våren går igenom alla dessa klasser, skapar objekt och sätter dem i sammanhanget;
  • Om automatisk konfiguration av någon anledning inte passar oss använder vi Java-baserad konfiguration
  • I det här fallet skapar vi en vanlig Java-klass vars metoder returnerar de objekt vi behöver. Vi markerar den här klassen med anteckningen @Configurationom vi ska skanna hela paketet istället för att ange en specifik klass med konfigurationen när vi skapar sammanhanget
  • Metoderna i denna klass som returnerar bönor är markerade med @Beananteckningen
  • Om vi ​​vill aktivera automatisk skanning när vi använder Java-baserad konfiguration använder vi anteckningen @ComponentScan.
Om den här artikeln har varit fullständigt förvirrande, försök att läsa den om ett par dagar. Eller om du är på en av de tidiga nivåerna av CodeGym, kan det vara lite tidigt för dig att studera Spring. Du kan alltid återvända till den här artikeln lite senare när du känner dig mer säker på dina Java-programmeringskunskaper. Om allt är klart kan du försöka konvertera ditt husdjursprojekt till våren :) Om vissa saker är tydliga men andra inte är det, snälla lämna en kommentar :) Låt mig veta dina förslag och kritik, om jag gick fel någonstans eller skrivit något nonsens :) I nästa artikel kommer vi att dyka abrupt in i spring-web-mvc och göra en enkel webbapplikation med Spring.
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION