Bevezetés a vezérlés és a függőségi injekció inverziójához tavasszal
1. Áttekintés
Ebben a cikkben bemutatjuk az IoC (Inversion of Control) és a DI (Dependency Injection) fogalmait, majd megnézzük, hogyan valósulnak meg ezek a tavaszi keretrendszerben.
2. Mi az ellenőrzés inverziója?
A vezérlés inverziója a szoftvertervezés egyik alapelve, amely révén a program objektumainak vagy részeinek vezérlése átkerül egy tárolóba vagy keretrendszerbe. Leggyakrabban az objektum-orientált programozás keretében használják.
A hagyományos programozással ellentétben, amelyben az egyéni kódunk hív egy könyvtárba, az IoC lehetővé teszi a keretrendszer számára, hogy átvegye az irányítást a program folyamata felett, és hívásokat kezdeményezzen az egyedi kódunkra. Ennek engedélyezéséhez a keretrendszerek absztrakciókat használnak, beépített további viselkedéssel. Ha hozzá akarjuk adni a saját viselkedésünket, akkor ki kell terjesztenünk a keretrendszer osztályait, vagy beépítenünk kell a saját osztályainkat.
Ennek az architektúrának az előnyei:
- a feladat végrehajtásának elválasztása a végrehajtástól
- megkönnyítve a különböző megvalósítások közötti váltást
- egy program nagyobb modularitása
- könnyebb tesztelni a programot egy komponens izolálásával vagy annak függőségének kigúnyolásával, és lehetővé teszi az alkatrészek kommunikációját szerződések útján
A vezérlés inverziója különféle mechanizmusokkal érhető el, például: Stratégia tervezési minta, Szolgáltatás kereső minta, Gyári minta és Dependency Injection (DI).
Legközelebb megnézzük a DI-t.
3. Mi a függőség injekciója?
A függőség-injektálás az IoC megvalósításának mintája, ahol az inverz vezérlő az objektum függőségeinek beállítása.
A tárgyak más tárgyakkal való összekapcsolása, vagy a tárgyakba más tárgyakba történő „befecskendezése” az összeszerelő, nem pedig maguk a tárgyak által történik.
Így hozhat létre objektumfüggőséget a hagyományos programozásban:
public class Store {private item item; public Store () {item = new ItemImpl1 (); }}
A fenti példában példát kell mutatnunk a Tétel interfész a Bolt osztály maga.
A DI használatával átírhatjuk a példát anélkül, hogy meghatároznánk a megvalósítását Tétel hogy szeretnénk:
public class Store {private item item; public Store (Cikk elem) {this.item = item; }}
A következő szakaszokban meglátjuk, hogyan tudjuk biztosítani a megvalósítását Tétel metaadatokon keresztül.
Az IoC és a DI egyaránt egyszerű fogalmak, de mély következményekkel jár a rendszereink felépítésében, ezért érdemes megérteni őket.
4. A tavaszi IoC konténer
Az IoC-tároló az IoC-t megvalósító keretek közös jellemzője.
A tavaszi keretrendszerben az IoC-tárolót az interfész képviseli ApplicationContext. A Spring konténer feladata az úgynevezett objektumok példányosítása, konfigurálása és összeszerelése bab, valamint életciklusuk kezelése.
A tavaszi keretrendszer a ApplicationContext interfész - ClassPathXmlApplicationContext és FileSystemXmlApplicationContext - önálló alkalmazásokhoz, és WebApplicationContext webes alkalmazásokhoz.
A bab összeállításához a tároló konfigurációs metaadatokat használ, amelyek lehetnek XML konfiguráció vagy kommentárok formájában.
A konténer manuális példányosításának az egyik módja:
ApplicationContext context = új ClassPathXmlApplicationContext ("applicationContext.xml");
A tétel attribútumot a fenti példában használhatunk metaadatokat. Ezután a konténer elolvassa ezeket a metaadatokat, és felhasználja azokat a bab összeállításához futás közben.
A függőség befecskendezése tavasszal kivitelezőkön, telepítőkön vagy mezőkön keresztül végezhető.
5. Konstruktor alapú függőségi injekció
Konstruktor-alapú függőség-injektálás esetén a tároló meghív egy konstruktort olyan argumentumokkal, amelyek mindegyike egy általunk beállítani kívánt függőséget képvisel.
Spring minden argumentumot elsősorban típus szerint old meg, majd az attribútum neve és az index a pontosításhoz. Nézzük meg a bab konfigurációját és annak függvényeit kommentárokkal:
@Configuration public class AppConfig {@Bean public item1 () {return new ItemImpl1 (); } @Bean public store store () {return new Store (item1 ()); }}
A @ Konfiguráció az annotáció azt jelzi, hogy az osztály a babdefiníciók forrása. Hozzáadhatjuk több konfigurációs osztályhoz is.
A @Bab annotációt használnak a bab meghatározására szolgáló módszeren. Ha nem adunk meg egyedi nevet, akkor a bab neve alapértelmezés szerint a metódus neve lesz.
Az alapértelmezett babért szingli hatókör, Spring először ellenőrzi, hogy létezik-e a bab gyorsítótárazott példánya, és csak akkor hoz létre újat, ha nem. Ha a prototípus hatókört, a tároló új bab példányt ad vissza minden metódushíváshoz.
A bab konfigurációjának létrehozásának másik módja az XML konfiguráció:
6. Szetter alapú függőségi injekció
A szetter alapú DI esetén a tároló meghívja osztályunk szetter metódusait, miután egy argumentum nélküli konstruktort vagy egy argumentum nélküli statikus gyári metódust hívott meg a bab példázására. Hozzuk létre ezt a konfigurációt kommentárok segítségével:
@Bean public store store () {Store store = new Store (); store.setItem (item1 ()); visszatérő üzlet; }
XML-t is használhatunk a bab ugyanazon konfigurációjához:
Konstruktor alapú és szetter alapú injekció kombinálható ugyanazon bab esetében. A tavaszi dokumentáció a konstruktor-alapú befecskendezést javasolja a kötelező függőségeknél, és a szetter-alapú injekciót az opcionálisaknál.
7. Terepi alapú Függőségi injekció
Terepi alapú DI esetén injektálhatjuk a függőségeket úgy, hogy egy-vel jelöljük őket @Autowired kommentár:
public class Store {@Autowired private item item; }
A Bolt objektumot, ha nincs konstruktor vagy szetter módszer a Tétel bab, a tartály reflexióval fogja beadni az injekciót Tétel -ba Bolt.
Ezt XML konfigurációval is elérhetjük.
Ez a megközelítés egyszerűbbnek és tisztábbnak tűnhet, de nem ajánlott használni, mert van néhány hátránya, például:
- Ez a módszer a reflexió segítségével injektálja a függőségeket, ami költségesebb, mint a konstruktor vagy szetter alapú injektálás
- Nagyon könnyű folyamatosan hozzáadni több függőséget ezzel a megközelítéssel. Ha több argumentummal rendelkező konstruktor injekciót használna, azt gondolnánk, hogy az osztály több dolgot is megtesz, ami megsértheti az egységes felelősség elvét.
További információ a @Autowired annotáció a Wiring In Spring cikkben található.
8. Függőségek automatikus megadása
A vezetékezés lehetővé teszi, hogy a Spring konténer automatikusan meghatározza az együttműködő babok közötti függőségeket a definiált babok ellenőrzésével.
Négyféle mód van a bab automatikus bekapcsolására XML konfigurációval:
- nem: az alapértelmezett érték - ez azt jelenti, hogy a bab nem használ automatikus bekapcsolást, és kifejezetten meg kell neveznünk a függőségeket
- név szerint: az automatikus vezetékezés az ingatlan neve alapján történik, ezért a Spring egy babot keres, amelynek neve megegyezik a beállítandó tulajdonsággal
- byType: hasonló a név szerint autowiring, csak az ingatlan típusa alapján. Ez azt jelenti, hogy Spring olyan babot keres, amelynek azonos típusú tulajdonsága van. Ha több ilyen típusú bab van, a keretrendszer kivételt vet.
- konstruktőr: az automatikus vezetékezés a konstruktor argumentumai alapján történik, ami azt jelenti, hogy Spring ugyanolyan típusú babokat keres, mint a konstruktor argumentumai
Például írjuk be a tétel1 a fentiek szerint típus szerint meghatározott bab a bolt bab:
@Bean (autowire = Autowire.BY_TYPE) public class Store {private item item; public setItem (Item item) {this.item = item; }}
A bab segítségével is injekciózhatunk @Autowired megjegyzés az automatikus vezetékezéshez típus szerint:
public class Store {@Autowired private item item; }
Ha több, azonos típusú bab van, használhatjuk a @ Minősítő a babra név szerint hivatkozó kommentár:
public class Store {@Autowired @Qualifier ("item1") privát cikk; }
Most írjuk be a babot típus szerint az XML konfiguráción keresztül:
Ezután adjunk be egy nevű babot tétel ba,-be tétel tulajdona bolt bab név szerint XML-en keresztül:
Azt is felülbírálhatjuk, hogy a függőségeket kifejezetten konstruktor argumentumokkal vagy beállítókkal definiáljuk.
9. Lusta inicializált bab
Alapértelmezés szerint a tároló az összes szingulbabot létrehozza és konfigurálja az inicializálás során. Ennek elkerülése érdekében használhatja a lusta-init attribútum értékkel igaz a bab konfigurációján:
Ennek következtében a tétel1 A babot csak akkor inicializáljuk, amikor először kérjük, és nem az indításkor. Ennek előnye a gyorsabb inicializálási idő, de a kompromisszum az, hogy a konfigurációs hibákat csak a bab kérése után lehet felfedezni, ami több órát vagy akár napokat is igénybe vehet, miután az alkalmazás már fut.
10. Következtetés
Ebben a cikkben bemutattuk a vezérlés inverziójának és a függőség-injektálás fogalmait, és példákat mutattunk rájuk a tavaszi keretrendszerben.
Ezekről a fogalmakról Martin Fowler cikkeiben olvashat bővebben:
- A kontrolltartályok és a függőségi injekciós minta inverziója.
- A vezérlés inverziója
És többet megtudhat az IoC és a DI tavaszi megvalósításáról a Spring Framework Reference Documentation-ban.