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.