Sa nakaraang artikulo , maikli kong ipinaliwanag kung ano ang Spring at kung ano ang beans at konteksto. Ngayon ay oras na upang subukan ito. Gagawin ko ito gamit ang IntelliJ IDEA Enterprise Edition. Ngunit lahat ng aking mga halimbawa ay dapat ding gumana sa libreng IntelliJ IDEA Community Edition. Sa mga screenshot, kung nakita mong mayroon akong ilang window na wala ka, huwag mag-alala — hindi ito mahalaga para sa proyektong ito :)
Una, lumikha ng walang laman na proyekto ng Maven. Ipinakita ko kung paano gawin ito sa artikulo sa link na ito . Basahin hanggang sa mga salitang " Oras na para i-convert natin ang aming proyekto sa Maven sa isang proyekto sa web. " — pagkatapos nito, ipinapakita ng artikulo kung paano gumawa ng isang proyekto sa web, ngunit hindi namin iyon kailangan sa ngayon. Sa src/main/javafolder, lumikha ng isang pakete (sa aking kaso, tinawag ko itong "
Sa window sa kaliwa, makikita mo ang istraktura ng proyekto kasama ang pakete at ang

en.codegym.info.fatfaggy.animals
. Maaari mo itong tawagan kahit anong gusto mo. Basta huwag kalimutang palitan ang aking pangalan ng pakete ng iyong pangalan ng pakete sa lahat ng tamang lugar. Ngayon lumikha ng Main
klase at magdagdag ng isang paraan
public static void main(String[] args) {
...
}
Pagkatapos nito, buksan ang pom.xml file at idagdag ang dependencies
seksyon. Pumunta ngayon sa repositoryo ng Maven at hanapin ang konteksto ng Spring para sa pinakabagong stable na bersyon. Ilagay ang nahanap namin sa dependencies
seksyon. Inilarawan ko ang prosesong ito nang mas detalyado sa ibang artikulo ng CodeGym na ito (tingnan ang seksyong pinamagatang " Pagkonekta ng mga dependency sa Maven "). Pagkatapos ay mahahanap at ida-download mismo ng Maven ang mga kinakailangang dependencies. Sa huli, dapat kang makakuha ng ganito: 
Main
klase. Ipinapakita ng gitnang window kung paano ako hinahanap ng pom.xml. Nagdagdag din ako ng propertiesseksyon dito. Sinasabi ng seksyong ito kay Maven kung aling bersyon ng Java ang ginagamit ko sa aking mga source file at kung aling bersyon ang isasama. Ito ay para lang hindi ako bigyan ng babala ng IDEA na gumagamit ako ng lumang bersyon ng Java. Ito ay opsyonal :) Nilinaw ng tamang window na kahit na ikinonekta lang namin ang spring-context module, awtomatiko itong hinila sa spring-core, spring-beans, spring-aop at spring-expression na mga module. Maaari naming ikonekta ang bawat module nang hiwalay, na nagsusulat ng dependency para sa bawat module na may tahasang bersyon sa pom.xml file, ngunit sa ngayon ay masaya kami sa mga bagay kung ano ang mga ito. Ngayon lumikha ng entities
package at lumikha ng 3 mga klase dito: Cat
, Dog
, Parrot
. Bigyan natin ng pangalan ang bawat hayop (private String name
— maaari mong i-hardcode ang ilang mga halaga doon). Ang mga getter/setter ay pampubliko. Ngayon lumipat kami sa Main
klase at ang main()
pamamaraan, at sumulat kami ng ganito:
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());
}
Una, lumikha kami ng isang bagay sa konteksto, na nagsasabi sa tagabuo kung aling pakete ang titingnan upang makahanap ng mga beans. Sa madaling salita, dadaan ang Spring sa package na ito at susubukang maghanap ng mga klase na may marka ng mga espesyal na anotasyon na nagpapahiwatig na sila ay beans. Pagkatapos ay lumilikha ito ng mga bagay ng mga klase na ito at inilalagay ang mga ito sa konteksto. Pagkatapos nito, nakakakuha kami ng pusa mula sa kontekstong ito. Tumawag kami sa object ng konteksto upang bigyan kami ng isang bean (object), na nagpapahiwatig ng klase ng bagay na gusto namin (sa pamamagitan ng paraan, maaari rin naming tukuyin ang mga interface, hindi lamang mga klase). Pagkatapos nito, ibinabalik ng Spring ang isang object ng hiniling na klase, na pagkatapos ay i-save namin sa isang variable. Susunod, hinihiling namin kay Spring na kumuha kami ng isang bean na tinatawag na "aso". Kapag ang Spring ay lumikha ng isangDog
object, binibigyan nito ang object ng karaniwang pangalan (maliban kung ang nilikhang bean ay tahasang binigyan ng pangalan), na siyang pangalan ng klase ngunit may paunang maliit na titik. Sa kasong ito, ang aming klase ay tinatawag na Dog
, kaya ang pangalan ng bean ay "aso". Kung kailangan namin ng isang BufferedReader
bagay doon , ang Spring ay tatawagin itong "bufferedReader". At dahil hindi 100% tiyak ng Java kung aling klase ang gusto natin, ibinabalik nito ang isang Object
bagay, na kung saan manu-mano naming inihagis sa nais na uri, ibig sabihinDog
. Ang opsyon kung saan ang klase ay tahasang ipinahiwatig ay mas maginhawa. Ang pangatlong opsyon ay ang kumuha ng bean ayon sa pangalan ng klase at sa pangalan ng bean. Posible na ang konteksto ay maaaring magkaroon ng ilang beans ng isang klase. Upang ipahiwatig ang partikular na bean na kailangan namin, ipinapahiwatig namin ang pangalan nito. Dahil tahasan din naming ipinapahiwatig ang klase dito, hindi na namin kailangang magsagawa ng cast. MAHALAGA!Kung makakita ang Spring ng ilang beans na tumutugma sa aming mga kinakailangan, hindi nito matukoy kung aling bean ang ibibigay sa amin, kaya magtapon ito ng exception. Alinsunod dito, upang maiwasan ang sitwasyong ito, dapat mong subukan na maging tiyak hangga't maaari sa pagsasabi sa Spring kung aling bean ang kailangan mo. Kung hahanapin ng Spring ang konteksto nito at nabigong makahanap ng isang bean na tumutugma sa aming mga kinakailangan, maglalagay din ito ng exception. Sa wakas, ipinapakita lang namin ang mga pangalan ng aming mga hayop upang i-verify na nakuha namin talaga ang mga bagay na kailangan namin. Ngunit kung patakbuhin natin ang programa ngayon, makikita natin na ang Spring ay hindi masaya — hindi nito mahanap ang mga hayop na kailangan natin sa konteksto nito. Ito ay dahil hindi nito nilikha ang mga beans na ito. Gaya ng sinabi ko dati, kapag nag-scan ng mga klase ang Spring, hinahanap nito ang sarili nitong mga anotasyon sa Spring. At kung hindi mahanap ng Spring ang mga anotasyong ito, hindi Tisipin na ang mga klaseng ito ay tumutugma sa mga beans na kailangan nitong likhain. Ang pag-aayos nito ay nangangailangan lamang ng pagdaragdag ng@Component
anotasyon sa harap ng bawat klase ng ating hayop.
@Component
public class Cat {
private String name = "Oscar";
...
}
Pero meron pa. Kung kailangan naming tahasang sabihin sa Spring na ang bean para sa klase na ito ay dapat magkaroon ng isang partikular na pangalan, ipinapahiwatig namin ang pangalan sa mga panaklong pagkatapos ng anotasyon. Halimbawa, para sabihin sa Spring na ibigay ang pangalang " parrot-polly
" sa parrot bean, na siyang pangalang gagamitin namin para makuha ang parrot na ito sa main
pamamaraan, dapat kaming gumawa ng ganito:
@Component("parrot-polly")
public class Parrot {
private String name = "Polly";
...
}
Ito ang buong punto ng awtomatikong pagsasaayos . Isusulat mo ang iyong mga klase, markahan ang mga ito ng mga kinakailangang anotasyon, at sabihin sa Spring ang package na mayroon ang iyong mga klase. Ito ang package na tatakbo sa framework upang mahanap ang mga anotasyon at lumikha ng mga bagay ng mga klaseng ito. Siyanga pala, ang Spring ay hindi lamang naghahanap ng @Component
mga anotasyon, kundi pati na rin sa lahat ng iba pang anotasyon na nagmamana ng isang ito. Halimbawa, @Controller
, @RestController
, @Service
, @Repository
, at higit pa, na ipakikilala namin sa mga artikulo sa hinaharap. Ngayon ay susubukan naming gawin ang parehong bagay gamit ang Java-based na configuration . Upang makapagsimula, alisin ang@Component
mga anotasyon mula sa aming mga klase. Upang gawing mas mahirap ang mga bagay, isipin na hindi namin isinulat ang mga klase na ito, kaya hindi namin madaling baguhin ang mga ito, na nangangahulugang hindi kami makakapagdagdag ng mga anotasyon. Parang naka-package ang mga klaseng ito sa ilang library. Sa kasong ito, walang paraan para sa amin na i-edit ang mga klase na ito upang makilala sila ng Spring. Ngunit kailangan namin ng mga bagay ng mga klase na ito! Dito kailangan namin ng configuration na nakabatay sa Java upang malikha ang mga bagay. Upang makapagsimula, lumikha ng isang package na may pangalan tulad ng configs
. Sa package na ito, lumikha ng isang ordinaryong Java class, tulad ng MyConfig
, at markahan ito ng @Configuration
anotasyon.
@Configuration
public class MyConfig {
}
Ngayon ay kailangan nating i-tweak ang main()
pamamaraan, binabago kung paano tayo gumagawa ng konteksto. Maaari naming tahasang ipahiwatig kung aling klase ang may aming pagsasaayos:
ApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
Kung mayroon kaming iba't ibang klase na lumilikha ng beans at gusto naming ikonekta ang ilan sa mga ito nang sabay-sabay, ipinapahiwatig lang namin ang lahat doon, na pinaghihiwalay ng mga kuwit:
ApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class, MyAnotherConfig.class);
At kung marami kami sa kanila at gusto naming ikonekta silang lahat nang sabay-sabay, ipinapahiwatig lang namin ang pangalan ng package na nilalaman ng mga ito:
ApplicationContext context =
new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.configs");
Sa kasong ito, dadaan ang Spring sa package at hahanapin ang lahat ng klase na minarkahan ng @Configuration
anotasyon. Well, at kung mayroon kaming isang malaking programa kung saan ang mga pagsasaayos ay nahahati sa iba't ibang mga pakete, pagkatapos ay ipinapahiwatig lamang namin ang isang listahan ng mga pangalan ng mga pangalan ng mga pakete na naglalaman ng mga pagsasaayos:
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");
O ang pangalan ng isang package na karaniwan para sa kanilang lahat:
ApplicationContext context =
new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals");
Magagawa mo ito gayunpaman gusto mo, ngunit tila sa akin na ang pinakaunang opsyon, na nagpapahiwatig lamang ng isang klase na may mga pagsasaayos, ay pinakaangkop sa aming programa. Kapag gumagawa ng konteksto, hinahanap ng Spring ang mga klase na may marka ng @Configuration
anotasyon at gagawa ng sarili nitong mga bagay ng mga klaseng ito. Sinusubukan nitong tawagan ang mga pamamaraan na may markang @Bean
anotasyon, na nangangahulugan na ang mga pamamaraang ito ay nagbabalik ng mga beans (mga bagay) na idaragdag ng Spring sa konteksto. At ngayon gagawa kami ng beans para sa isang pusa, aso, at loro sa aming klase na may configuration na nakabatay sa Java. Ito ay medyo simpleng gawin:
@Bean
public Cat getCat() {
return new Cat();
}
Dito, manu-mano naming ginagawa ang aming pusa at ibinibigay ito sa Spring, na pagkatapos ay hawak ang aming bagay sa konteksto nito. Dahil hindi namin tahasang binigyan ng pangalan ang aming bean, bibigyan ito ng Spring ng parehong pangalan bilang ang pangalan ng pamamaraan. Sa aming kaso, ang cat bean ay tatawaging " getCat
". Ngunit dahil ginagamit namin ang klase, hindi ang pangalan, upang makuha ang cat bean sa main
pamamaraan, ang pangalan ng bean ay hindi mahalaga sa amin. Katulad nito, lumikha ng isang dog bean, isinasaisip na ang Spring ay magbibigay ng pangalan ng pamamaraan sa bean. Upang tahasang pangalanan ang aming parrot bean, ipinapahiwatig lang namin ang pangalan nito sa mga panaklong pagkatapos ng @Bean
anotasyon:
@Bean("parrot-polly")
public Object weNeedMoreParrots() {
return new Parrot();
}
Tulad ng nakikita mo, dito ko ipinahiwatig ang isang Object
uri ng pagbabalik at binigyan ang pamamaraan ng isang arbitrary na pangalan. Hindi ito nakakaapekto sa pangalan ng bean, dahil tahasan naming tinukoy ang pangalan dito. Gayunpaman, mas mainam na magpahiwatig ng mas marami o hindi gaanong makabuluhang halaga ng pagbabalik at pangalan ng pamamaraan. Gawin ito kung walang ibang dahilan kundi gawin ang iyong sarili ng isang pabor kapag binuksan mo muli ang proyekto sa isang taon. :) Ngayon isaalang-alang ang sitwasyon kung saan kailangan namin ng isang bean upang lumikha ng isa pang bean . Halimbawa, ipagpalagay na gusto namin ang pangalan ng pusa sa cat bean ay ang pangalan ng loro kasama ang string na "-killer". Walang problema!
@Bean
public Cat getCat(Parrot parrot) {
Cat cat = new Cat();
cat.setName(parrot.getName() + "-killer");
return cat;
}
Dito makikita ng Spring na upang malikha ang bean na ito, ang balangkas ay kailangang pumasa sa naunang nilikha na parrot bean. Alinsunod dito, aayusin nito ang kinakailangang hanay ng mga tawag sa pamamaraan: una, ang paraan ng paglikha ng parrot ay tinatawag at pagkatapos ay ipinapasa ng balangkas ang bagong loro sa paraan ng paglikha ng pusa. Dito gumaganap ang dependency injection : Spring mismo ang nagpapasa ng kinakailangang parrot bean sa aming pamamaraan. Kung magalit ang IDEA tungkol sa parrot
variable, huwag kalimutang baguhin ang uri ng pagbabalik ng paraan ng paggawa ng parrot mula Object
sa Parrot
. Bilang karagdagan, ang Java-based na configuration ay nagbibigay-daan sa iyong patakbuhin ang anumang Java codesa iyong mga pamamaraan sa paggawa ng bean. Maaari mo talagang gawin ang anumang bagay: lumikha ng iba pang mga auxiliary na bagay, tumawag sa anumang iba pang mga pamamaraan, kahit na ang mga hindi minarkahan ng Spring annotation, lumikha ng mga loop, Boolean na kundisyon — anuman ang naiisip! Hindi lahat ito ay posible sa awtomatikong pagsasaayos, at mas mababa pa sa XML configuration. Ngayon isaalang-alang natin ang isang problema na medyo mas masaya. Polymorphism at mga interface :) Gagawa kami ng WeekDay
interface at gagawa kami ng 7 klase na nagpapatupad ng interface na ito: Monday
, Tuesday
, Wednesday
, Thursday
, Friday
, Saturday
, Sunday
. Bibigyan namin ang interface ng isang String getWeekDayName()
paraan, na magbabalik ng pangalan ng araw ng linggo para sa kaukulang klase. Sa madaling salita, Monday
babalik ang klase "Monday
", atbp. Sa pagsisimula ng application, ipagpalagay na ang aming gawain ay maglagay ng bean na tumutugma sa kasalukuyang araw ng linggo sa konteksto. Hindi beans para sa lahat ng klase na nagpapatupad ng interface — ang isang bean lang na kailangan namin. Maaari WeekDay
kang gawin iyan tungkol sa ganito:
@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();
}
}
Narito ang uri ng pagbabalik ay ang aming interface. Ang pamamaraan ay nagbabalik ng isang bona fide object ng isa sa mga klase na nagpapatupad ng interface, depende sa kasalukuyang araw ng linggo. Ngayon ay maaari nating gawin ang sumusunod sa main()
pamamaraan:
WeekDay weekDay = context.getBean(WeekDay.class);
System.out.println("Today is " + weekDay.getWeekDayName() + "!");
Para sa akin, ang programa ay nagsasabi sa akin na ito ay Linggo :) Kumpiyansa ako na kung patakbuhin ko ang programa bukas, ang konteksto ay maglalaman ng isang ganap na naiibang bagay. Tandaan na nakukuha namin ang bean gamit lamang ang interface: context.getBean(WeekDay.class)
. Hahanapin ng Spring ang konteksto nito para sa bean na nagpapatupad ng interface, at ibabalik ito. Pagkatapos ay lumalabas na ang aming WeekDay
variable ay nagtatapos sa isang bagay sa Linggo, at ang pamilyar na konsepto ng polymorphism ay nalalapat habang nagtatrabaho kami sa variable na ito. :) Ngayon ang ilang mga salita tungkol sa pinagsamang diskarte , kung saan ang ilang mga bean ay awtomatikong nilikha ng Spring, ang ilan ay sa pamamagitan ng pag-scan ng mga pakete para sa mga klase na may @Component
anotasyon, at ang iba sa pamamagitan ng Java-based na configuration. Habang isinasaalang-alang namin ito, babalik kami sa orihinal na bersyon, kung saan ang Cat
, Dog
, atParrot
ang mga klase ay minarkahan ng @Component
anotasyon. Ipagpalagay na gusto naming gumawa ng beans para sa aming mga hayop sa pamamagitan ng awtomatikong pag-scan ng Spring sa entities
package, ngunit gusto rin naming gumawa ng bean sa araw ng linggo, tulad ng ginawa namin. Ang kailangan mo lang gawin ay idagdag ang @ComponentScan
anotasyon sa antas ng MyConfig
klase, na ipinapahiwatig namin kapag lumilikha ng konteksto sa main()
, at ipahiwatig sa panaklong ang package na kailangang i-scan at awtomatikong lumikha ng beans ng mga kinakailangang klase:
@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();
}
}
}
Kapag lumilikha ng konteksto, nakikita ng Spring na kailangan nitong iproseso ang MyConfig
klase. Pumasok ito sa klase at nakitang kailangan nitong i-scan ang en.codegym.info.fatfaggy.animals.entities
package na " " at lumikha ng mga beans ng mga klaseng iyon, pagkatapos nito isagawa ang pamamaraan MyConfig
ng klase getDay()
at magdagdag ng WeekDay
bean sa konteksto. Sa main()
pamamaraan, mayroon na kaming access sa lahat ng beans na kailangan namin: parehong mga bagay na hayop at isang bean na may araw ng linggo. Kung sakaling kailanganin mong kunin din ang Spring ng ilang XML configuration file, maaari mong gawin ang iyong sariling paghahanap sa web upang makahanap ng paliwanag :) Buod:
- Subukang gumamit ng awtomatikong pagsasaayos
- Sa panahon ng awtomatikong pagsasaayos, ipahiwatig ang pangalan ng pakete na naglalaman ng mga klase na ang mga bean ay kailangang gawin
- Ang mga klase na ito ay minarkahan ng
@Component
anotasyon - Ang Spring ay tumatakbo sa lahat ng mga klase na ito, lumilikha ng mga bagay, at inilalagay ang mga ito sa konteksto;
- Kung hindi angkop sa amin ang awtomatikong pagsasaayos sa ilang kadahilanan, gumagamit kami ng configuration na nakabatay sa Java
- Sa kasong ito, lumikha kami ng isang ordinaryong Java class na ang mga pamamaraan ay nagbabalik ng mga bagay na kailangan namin. Minarkahan namin ang klase na ito ng
@Configuration
anotasyon kung i-scan namin ang buong package sa halip na magpahiwatig ng isang partikular na klase na may configuration kapag lumilikha ng konteksto - Ang mga pamamaraan ng klase na ito na nagbabalik ng beans ay minarkahan ng
@Bean
anotasyon
@ComponentScan
anotasyon.
GO TO FULL VERSION