A Java Spring Framework erős, hasznos és népszerű eszköz a Java-fejlesztők számára. Azonban a kezdőknek segítségre van szükségük a keretrendszer és a működéséről szóló, számos weboldalon és könyvben elérhető hatalmas mennyiségű információ megértéséhez. Éppen ezért a legfontosabb szempontokat gyűjtöttük össze ebben az útmutatóban a Java Spring Frameworkkel való munkavégzéssel kapcsolatban. Ennek segítségével az újoncok is strukturálhatják a tudásukat, és gyorsabban elsajátíthatják ezt a keretrendszert. Emellett, ha még strukturáltabb tanulási módszert szeretnél követni, iratkozz be az ingyenes Java-tanfolyamunkra.
Mi az a Spring Framework?
A Java Spring Framework lényegében az Te Java-fejlesztői munkádat egyszerűsíti le, mivel lehetővé teszi az egyes funkciók gyorsabb és biztonságosabb megvalósítását. Tekintsd egy megbízható társnak a programozás világában, amelynek segítségével hatékonyabban tudsz dolgozni, és kreativitásodat is szabadjára engedheted. A Spring alapelvét a minimális beavatkozás képezi; ahogyan azt a hivatalos weboldal is állítja, a Spring a Java programozást elérhetőbbé és hatékonyabbá teszi.
A Spring Framework használatának előnyei
- Egyszerűsített fejlesztés: A Spring olyan robusztus funkciókkal csökkenti a Java-fejlesztés összetettségét, mint a függőségi injektálás és az aspektusorientált programozás.
- Fokozott hatékonyság: A Java Spring kiterjedt könyvtárai és sablonjai leegyszerűsítik a fejlesztők mindennapi feladatait, amely gyorsabb fejlesztési ciklusokat tesz lehetővé.
- Fokozott tesztelhetőség: A Spring az egységtesztelés és mocking keretrendszerek támogatásával teszi lehetővé, hogy a fejlesztők átfogó tesztcsomagokat írhassanak, biztosítva ezzel az alkalmazások megbízhatóságát.
Spring Framework modulok
A Spring keretrendszer kb. 20 különböző modulból áll, amelyek mindegyike egyedi szerepet tölt be a keretrendszeren belül. A „springek” modulárisak: a programozók a különböző modulokat egymástól függetlenül vagy együttesen is használhatják robusztus alkalmazások létrehozásához. Íme a Spring modulok fő csoportja:
- Alaptároló (Core Container): Ez a core, beans, context és expression language modulokat foglalja magában, amelyek a keretrendszer alapvető részeit biztosítják.
- Webmodul: A Spring MVC és WebSocket modulokat tartalmazza, amelyek a webes alkalmazások fejlesztését és a valós idejű kommunikációt támogatják.
- Adat-hozzáférés / Integráció (Data Access / Integration): Olyan modulokból áll, mint a JDBC, ORM (Object-Relational Mapping), JMS (Java Messaging Service) és Transaction Management, amelyek konzisztens adatelérési stratégiát biztosítanak, és olyan népszerű keretrendszerekkel integrálhatók, mint a Hibernate és a JPA.
- AOP, Aspektusok és Instrumentáció (AOP, Aspects and Instrumentation): Támogatja az aspektusorientált programozás megvalósítását, lehetővé téve az átfogó problémák elkülönítését.
- Tesztelés (Tests): Átfogó tesztelési támogatást nyújt az alkalmazások megbízhatóságának és minőségének biztosításához.
Mivel nem fogjuk ebben a cikkben az összes modult részletesen tárgyalni, az alapvető Core modullal fogunk foglalkozni. Segítséget nyújtunk a Spring Framework alapvető koncepcióinak megértésében Java nyelven, pl. hogyan kezeli a függőségeket és hogyan kerül integrálásra az alkalmazásokban.
A Spring Framework kulcsfogalmai
A Java Spring világába történő utazásod megkezdésekor számos új kifejezéssel találkozhatsz, amelyek komoly fejfájást okozhatnak Neked. Sajnos sok kezdőknek szóló útmutató hajlamos átugrani ezeket a kritikus kifejezéseket, feltételezve, hogy már ismered őket. Ugyanakkor elengedhetetlen, hogy már az elején kellő időt szánjunk a kulcsfogalmakra:
- Keretrendszer. Ez egy olyan platform, amely kész megoldásokat kínál a szabványos alkalmazáskonfigurációs feladatokra. A fejlesztők a keretrendszert így alkalmazásaikba integrálhatják, és az alaplogikára tudnak koncentrálni.
- Függőség. A „függőség” néven is ismert osztály egy rendszeren belüli másik osztály megfelelő működéséhez nélkülözhetetlen osztályra utal.
- Annotációk. Ez egy fordító vagy értelmező által használt rövidítés a forráskódban. A Spring kontextusában ezt a keretrendszer végzi.
- Bean. Meghatározott konvenciók szerint kialakított Java-osztály. A Bean-ek segítenek az objektumok csoportosításában, ami az adatátvitelt leegyszerűsíti.
A Spring Framework alkalmazása Java-ban
A sokoldalú Java Spring keretrendszer különböző forgatókönyvekben alkalmazható:
- Webes alkalmazások: A Spring MVC (Model-View-Controller) a robusztus webalkalmazások létrehozását a problémák egyértelmű szétválasztásával támogatja.
- Mikroszolgáltatások: A Spring Boot leegyszerűsíti a mikroszolgáltatások fejlesztését, egyből használatra kész környezetet biztosítva.
- Adathozzáférés: Az adatbázisok széles körét támogató Spring Data megkönnyíti az adathozzáférést és az adatmanipulációt.
- Biztonság: A Spring Security átfogó biztonsági szolgáltatásokat nyújt, a hitelesítést és az engedélyezést is beleértve.
- Felhőalkalmazások: A Spring Cloud eszközöket biztosít az osztott rendszerek felépítéséhez és a felhőalapú telepítések kezeléséhez.
Spring Framework funkciók: IoC & DI
A kontroll megfordítása és függőségi injektálás
A Springet gyakran IoC konténerként is emlegetik. Amellett, hogy ez igaz, nem teljesen fedi le a keretrendszer funkcionalitását. Ahhoz, hogy az alapkoncepciót és a jelentőségét megragadjuk, először is meg kell értenünk az Inversion of Control (IoC) fogalmát. Ennek szemléltetéséhez egy Spring nélküli program vizsgálatát javasoljuk.
A kontroll megfordítása képezi az objektumorientált programozás egyik alapelvét, amely a kód modularitását növeli és a komponensek közötti függőségeket csökkenti. Mikor az A osztály működése a B osztályon múlik, akkor az A osztály függővé válik a B osztálytól. Itt lényegében úgy válik az egyik osztály függővé a másiktól, mint ahogyan egy autó függ a motorjától.
Például az IoC nélküli kódot az alábbi ábra szemlélteti. A Motor osztály tartalmazza a „run” (futtatás) metódust, amely pl. az autó motorjának beindítását végzi. A drive() metódus aktiválásához először létre kell hoznunk a Motor osztály egy példányát, majd ennek megfelelően meg kell győződnünk arról, hogy a motor működőképes-e.
Ez a megközelítés két jelentős hátránnyal jár:
- egyrészt magas szintű kapcsolat áll fenn az osztályok között, amely lehetetlenné teszi az egymástól független fejlesztést és módosítást;
- másrészt az alkalmazás kódját egészében véve nehéz módosítani, karbantartani és frissíteni.
A példában szereplő kód azonban egy interfész használatával javítható. Ennek köszönhetően a motor könnyen módosítható (akár egy V8Motor-ra) a drive() metódus módosítása nélkül. Azonban a választott megvalósítás kezelése – főként nagyszámú telepítés esetén – továbbra is kihívást jelent.
Ebben segít az IoC! Az kontroll megfordításának végrehajtásával a függőségek létrehozása az osztályon kívülre kerül, így nincs szükség új operátorra minden egyes elem létrehozásakor. Az IoC lehetővé teszi, hogy a forráskód módosítása nélkül, külső forrásból adjunk hozzá új függőségeket.
A Springben a függőségi injektálás (Dependency Injection, DI) a leggyakrabban használt megközelítés az IoC megvalósítására. A DI azonban a Spring keretrendszertől függetlenül is felhasználható. Az egyik ilyen módszer az alábbiakban szemléltetett Setter Injection: Itt egy setEngine() metódus kerül bevezetésre, amely lehetővé teszi a motor kívülről történő beadását, így nincs szükség minden egyes Motor objektum manuális létrehozására.
A függőségek a konstruktor alapú injektáláson keresztül is használhatók, amikor az argumentumok a konstruktoron keresztül kerülnek átadásra. Ahogy az alábbi ábrán látható, az IoC-nek köszönhetően kevesebb a függőség, ami megkönnyíti az osztályok módosítását és bővítését.
Azonban e fejlesztések ellenére még mindig szükség van az új operátor használatára az osztályok létrehozásához. Itt lép be a Spring keretrendszer.
Spring Beans
A Springben minden osztályt bean-nek nevezünk, hasonlóan a JavaBeans-hez, amelyek betartják az olyan standardokat, mint például a paraméterek nélküli konstruktor vagy a get- és set-metódusok. Bár a Spring bean-ek ezekkel az osztályokkal azonosak, ilyen szigorú szabályok nem vonatkoznak rájuk.
A bean-ek hatóköre
- @Scope(“singleton”). Alapértelmezés szerint a Spring bean-ek egytagú halmazok, ami azt jelenti, hogy az IoC konténer minden bean-ből egyetlen példányt tartalmaz. Ez biztosítja az erőforrások hatékony felhasználását, mivel a rendszer minden egyes későbbi kérésnél ugyanazt a hivatkozást adja vissza a már létrehozott objektumra vonatkozóan az adott bean esetében.
- @Scope(“prototype”). Az egytagú halmazzal ellentétben a prototípus hatókörök a bean-ből minden függőséghez új példányt hoznak létre. Ez akkor előnyös, ha minden egyes használat esetén a bean-ek különböző állapotaira van szükségünk. Fontos azonban megjegyezni, hogy a prototípus függőségek csak a megfelelő hatókörrel rendelkező komponenseken belül működnek jól. A prototípus függőségek használatát kerüljük az egytagú halmaz komponensekben, bár ez a korlátozás a Method Injection használatával megkerülhető (erről bővebben itt olvashatsz) .
- Hatókör webes alkalmazásokhoz. A webes alkalmazások külön hatókörökkel rendelkeznek, amelyek korlátozhatják egy objektum életciklusát. A hatókörök egy kérésen, munkameneten, servleten és websocket-en belül konfigurálhatók.
A bean életciklusának megértése
Egy bean több inicializálási lépésen megy keresztül, mielőtt elérhetővé válik. Életciklusának kezeléséhez két annotáció kerül felhasználásra:
- @PostConstruct. Ez az annotáció egy olyan metódust jelöl, amelyet közvetlenül a bean constructor után kell végrehajtani.
- @PreDestroy. A metódus a bean törlése előtt kerül lehívásra.
Ezek a módszerek nyújtanak segítséget az erőforrások növelésében vagy csökkentésében – egyesek az egytagú halmazoknál, mások a prototípusoknál működnek. A @PreDestroy módszer azonban a prototípus bean-ek esetében nem érhető el, mivel minden függőség külön objektummal rendelkezik.
Sztereotip annotációk Java Spring-ben
A Spring Frameworkben az annotációk kritikus szerepet játszanak a bean-ek definiálásában és kezelésében az alkalmazási kontextuson belül. A @Component annotáció az egyik elsődleges, erre a célra használt annotáció. Spring által kezelt komponensként jelöl meg egy osztályt, ami lehetővé teszi, hogy azt a Spring automatikusan felismerje és regisztrálja a komponensek vizsgálata során. A Spring hasonló célokat szolgáló, speciális, sztereotip annotációkat is biztosít, azonban további, az alkalmazás egyes rétegeire szabott szemantikát és funkciókat kínál.
A @Component a következő megfelelőkkel rendelkezik: @Controller, @Service és @Repository. Ezek azonban gyakorlatilag azonosak, és a @Component helyett jelölőként szolgálnak. Bár funkcionálisan hasonlóak, idővel mindegyik rendelkezhet egyedi tulajdonságokkal. Pl. a @Repository ügyesen kezeli a tárolók Dao-kivételeit. Kétség esetén javasoljuk a @Component használatát, mivel általános sztereotip annotációkkal szolgál. A speciális annotációk használata azonban javíthatja a kód olvashatóságát és szervezettségét, mivel egyértelműen jelzi az egyes komponensek alkalmazáson belül betöltött szerepét.
A Spring integrálása
Több lépést is kell követned a Spring IoC- és DI-funkciók erejének kihasználásához az alkalmazásodban:
- Konfiguráció fejlesztése a Spring számára: Először is hozz létre egy konfigurációs fájlt (gyakran az applicationContext.xml-lel vagy a Java Config @Configuration osztályok használatával), amelyben a bean-eket és függőségeiket tudod meghatározni.
- Az ApplicationContext meghatározása: Az ApplicationContext a Spring keretrendszer szíve: metaadatokat tárol a bean-ekről, és kezeli azok életciklusát. Itt konfigurálhatod az alkalmazás alkotóelemeit és azok kapcsolatait.
- Bean-ek kivonása az IoC konténerből: Miután a bean-ek definiálása az ApplicationContextben megtörtént, a bean-ek azonosítóik segítségével vagy típusaik szerint kinyerhetők a konténerből. A Spring kezeli ezeknek a bean-eknek az életciklusát, biztosítva, hogy szükség esetén rendelkezésre álljanak, és megfelelően „kitakarított” állapotban legyenek.
A Spring konfigurálása
Különböző konfigurációs lehetőségek állnak rendelkezésre, amelyek mindegyike befolyásolja az interfész kialakítását.
Konfiguráció XML-en keresztül
A kód a Spring nélküli kódhoz hasonlít, minimális hatással. Egy XML konfiguráció a következőre hasonlíthat:
A kód a Spring névtérre való hivatkozással kezdődik, majd a bean-re vonatkozó deklarációk következnek:
- Motor. Az első bean pl. a V8Engine osztály egyik objektumának lekérdezésére hívható.
- Autó. Ez a bean a konstruktoron keresztül megvalósított motorra támaszkodik, bár ez egy setteren keresztül is megvalósítható.
Létre kell hoznod egy ‘ClassPathXmlApplicationContext’ osztályt, és át kell adnod a ‘config.xml’ fájlt argumentumként. Ezután kérd le a bean-autót a Spring-től. Ezt követően a keretrendszer a szükséges függőségeket automatikusan implementálni fogja. A config.xml konfigurációnak köszönhetően a Spring meg fogja érteni, hogy az autó motorja függőséggel rendelkezik. A fejlesztőnek így nincs szüksége arra, hogy az egyik osztály függőségét a másiktól adja meg a kódban.
Konfiguráció Annotációkon keresztül
A Springben a konfigurációkat annotációkkal is létrehozhatjuk. Ezek segítségével érti meg a keretrendszer, hogy a függőségek hol találhatók, és hogyan kell velük dolgozni. Az előző példa szerint a config.xml-ből eltávolíthatod az összes bean-ekre történő hivatkozást, majd hozzáadhatsz egy hivatkozást a csomag @Component annotáció részére történő átvizsgálásra.
Ezt követően a Spring a beanekre automatikusan a @Component annotációval jelölt osztályokként fog tekinteni. A függőségi injektálási pontokat a @Autowired annotációval kell jelölni.
A Spring 4.3 utáni verziókban az @Autowired alkalmazása a konstruktor esetében nem szükséges. Ha csak egy konstruktor van, a keretrendszer azt fogja meghatározni a függőségi alkalmazás pontjaként. Azonban, ha egy setteren annotációt állítunk be, explicit annotációkat kell megadnunk.
Java-konfiguráció
A Java konfiguráció megvalósításához töröld a config.xml fájlt, és a konfigurációt normál @Configuration annnotációval ellátott Java osztály segítségével definiáld. Definiáld a szükséges bean-eket ebben az osztályban.
Ennek a megközelítésnek az a fő hátránya, hogy a függőségek megvalósítását manuálisan kell konfigurálnod. Ugyanakkor szükségtelenné teszi az osztályokra vonatkozó annotációkat, mely az ApplicationContext implementációkra történő váltást megkönnyíti.
Az XML és az annotációk közötti választás esetén mindkét megközelítés előnyös lehet:
- Az XML-konfigurációkkal szétválaszthatod az alkalmazásbeállításokat és az üzleti logikát, ami kényelmes megoldást jelenthet. Ez így van, mivel a konfigurációkat kiveszed a kódból.
- Az annotációk a konfiguráció vizuális megjelenítését közvetlenül a kódban biztosítják, javítva ezáltal az olvashatóságot.
A modellek mindenesetre felcserélhetők. Kritikus fontosságú, hogy a fejlesztési folyamat során végig egy módszerhez ragaszkodj.
Az @Autowired használata függőségi injektáláshoz
A Spring integrációjának megértését követően annak legfontosabb jellemzőire és a keretrendszer alkalmazásra gyakorolt hatására összpontosíthatsz. A népszerű annotációk megértése fontos kiindulópontot jelent; ezek közül az @Autowired az egyik legelterjedtebb. Ezt az annotációt azonban sokszor helytelenül használják, ami gyakran zavart okoz. Ezért elengedhetetlen, hogy annak célját és a használati irányelveket világosan megértsd.
A @Autowired annotáció a függőségek beillesztésének folyamatát kezeli. Bármelyik telepítési pontra: akár konstruktorra, akár szetterre, akár mezőre is alkalmazható. Ezt követően a Spring egy ilyen ponttal rendelkező bean-t tud társítani. Az alábbi ábra a függőségi injektálásra mutat be egy példát egy @Autowired annotációval ellátott setteren keresztül.
Következő lépésként hozz létre egy Java konfigurációt és egy @ComponentScan annotációt. Ez kiküszöböli az explicit bean-deklarációk szükségességét a kódban.
Általánosságban az @Autowired három módszert kínál a függőségi injektáláshoz:
- Injektálás a konstruktoron keresztül. Ez a legjobb megoldás, ha kötelező a függőség vagy megváltoztathatatlannak kell lennie (az utolsó kulcsszó használatával). Ez a módszer leegyszerűsíti a több függőséggel rendelkező osztályok azonosítását. Ha a függőségek a konstruktoron keresztül kerülnek implementálásra, azonnal feltűnik a paraméterek nagy száma, ami nem tekinthető normális helyzetnek.
- Injektálás a setteren keresztül. Ez az opcionális függőségek vagy gyakran változó konfigurációk esetén alkalmazható, és a függőségek definiálását is lehetővé teszi a kezelői felületen. Ha azonban kritikus függőséghez használják, NullPointerExceptiont dobhat, és az alkalmazás összeomolhat. A kockázat minimálisra csökkentése érdekében használd a @Required annotációt.
- Injektálás a mezőn keresztül. Lehetséges eljárás, mégis érdemesebb elkerülni. Először is, ezzel a módszerrel nem teheted a függőséget megváltoztathatatlanná. Ugyanakkor nagyon egyszerűen adhatsz hozzá új függőségeket, ezért nagy a valószínűsége, hogy „szuperosztályokat” és a túlterhelt kódot fogsz létrehozni. Továbbá, ezzel a függőségi injektálással függőséget hozol létre az IoC konténertől, ami a konténer lecserélésére vagy eltávolítása esetén nagyszámú kód újraírására kényszerít. És végül, ez a módszer az egységtesztek írása során segítséget igényel a reflexióhoz.
Az első két módszer közötti választás még a keretrendszer alkotói között is vita tárgyát képezi. Ők a 4.0-s verzióig a settereket ajánlották. Ennek oka, hogy sok argumentum esetén egy konstruktor akár túl nagyra is nőhet (különösen, ha a tulajdonságok opcionálisak). Az utóbbi években azonban az ajánlások a konstruktorok javára változtak. Ezzel a megközelítéssel megváltoztathatatlan komponenseket hozhatsz létre, és biztosíthatod a szükséges függőségek megfelelő inicializálását. Mindazonáltal a legjobb megoldást kell kiválasztanod a projekted számára – vagy a két módszert akár kombinálhatod is.
Mi az Annotation @Qualifier?
Ha egy @Autowireddel megvalósított interfész több implementációval rendelkezik (pl. belsőégésű motor, elektromos motor stb.), hiba fog történni. Ennek a kétértelműségnek a feloldására a @Qualifier annotációt használd! Meg fogja mutatni a helyes implementációt a Spring számára.
További források
A Spring Framework széleskörű és összetett megoldásokat, valamint végtelen elemzési lehetőségeket és árnyalatokat kínál a Java programozásban. Ugyanakkor a fejlesztési feladatokat jelentősen leegyszerűsíti. Az objektumorientált elvek elsajátításával és a Spring szövevényes világának tanulmányozásával jelentős időt takaríthatsz meg a rutinfeladatok elvégzéséhez. További segítségért ld.:
Ha új vagy a Java világában, olvasd el a cikkünket arról, hogyan tanulhatod meg kezdőként a Java használatát!