Injekcia závislosti na kotline s kodeínom

1. Prehľad

V tomto článku si predstavíme Kodein - čistý rámec pre vstrekovanie závislostí Kotlin (DI) - a porovnáme ho s inými populárnymi rámcami DI.

2. Závislosť

Najskôr pridajme závislosť od kodeínu do našej pom.xml:

 com.github.salomonbrys.kodein kodein 4.1.0 

Upozorňujeme, že najnovšia dostupná verzia je k dispozícii buď v Maven Central, alebo jCenter.

3. Konfigurácia

Nižšie uvedený model použijeme na ilustráciu konfigurácie založenej na kodeíne:

trieda Controller (private val service: Service) class Service (private val dao: Dao, private val tag: String) interface Dao class JdbcDao: Dao class MongoDao: Dao

4. Typy väzieb

Kodein framework ponúka rôzne typy väzieb. Poďme sa bližšie pozrieť na to, ako fungujú a ako ich používať.

4.1. Singleton

S Singleton viazanie, cieľová fazuľa je lenivo inštancovaná pri prvom prístupe a znova použité pri všetkých ďalších požiadavkách:

var created = false; val kodein = Kodein {bind () so singletonom {MongoDao ()}} assertThat (vytvorené) .isFalse () val dao1: Dao = kodein.instance () assertThat (vytvorené) .isFalse () val dao2: Dao = kodein.instance () assertThat (dao1) .isSameAs (dao2)

Poznámka: môžeme použiť Kodein.instance () na získanie cieľovo riadených bôbov na základe typu statickej premennej.

4.2. Dychtivý Singleton

Je to podobné ako v prípade Singleton viazanie. Rozdiel je iba v tom inicializačný blok sa volá nedočkavo:

var created = false; val kodein = Kodein {bind () so singletonom {MongoDao ()}} assertThat (vytvorený) .isTrue () val dao1: Dao = kodein.instance () val dao2: Dao = kodein.instance () assertThat (dao1) .isSameAs (dao2)

4.3. Továreň

S Továreň väzba, inicializačný blok prijme argument a zakaždým sa z neho vráti nový objekt:

val kodein = Kodein {bind () so singletonom {MongoDao ()} bind () s továrňou {tag: String -> Service (instance (), tag)}} val service1: Service = kodein.with ("myTag"). instance () val service2: Service = kodein.with ("myTag"). instance () assertThat (service1) .isNotSameAs (service2)

Poznámka: môžeme použiť Kodein.instance () na konfiguráciu tranzitívnych závislostí.

4.4. Multiton

Multiton väzba je veľmi podobná Továreň viazanie. Rozdiel je iba v tom ten istý objekt sa vráti pre ten istý argument v ďalších hovoroch:

val kodein = Kodein {bind () so singletonom {MongoDao ()} bind () s multiton {tag: String -> Service (instance (), tag)}} val service1: Service = kodein.with ("myTag"). instance () val service2: Service = kodein.with ("myTag"). instance () assertThat (service1) .isSameAs (service2)

4.5. Poskytovateľ

Toto nie je arg Továreň väzba:

val kodein = Kodein {bind () s poskytovateľom {MongoDao ()}} val dao1: Dao = kodein.instance () val dao2: Dao = kodein.instance () assertThat (dao1) .isNotSameAs (dao2)

4.6. Inštancia

Môžeme zaregistrujte predkonfigurovanú inštanciu fazule v kontajneri:

val dao = MongoDao () val kodein = Kodein {bind () s inštanciou (dao)} val fromContainer: Dao = kodein.instance () assertThat (dao) .isSameAs (fromContainer)

4.7. Označovanie

Môžeme tiež zaregistrujte viac ako jednu fazuľu rovnakého typu pod rôznymi značkami:

val kodein = Kodein {bind ("dao1") so singletonom {MongoDao ()} bind ("dao2") so singletonom {MongoDao ()}} val dao1: Dao = kodein.instance ("dao1") val dao2: Dao = kodein.instance ("dao2") assertThat (dao1) .isNotSameAs (dao2)

4.8. Neustále

Toto je syntaktický cukor cez značenú väzbu a predpokladá sa ktoré sa majú použiť pre konfiguračné konštanty - jednoduché typy bez dedenia:

val kodein = Kodein {konštanta ("mágia") s 42} val zContainer: Int = kodein.instance ("magic") assertThat (fromContainer) .isEqualTo (42)

5. Separácia väzieb

Kodein nám umožňuje konfigurovať fazuľa v samostatných blokoch a kombinovať ich.

5.1. Moduly

Môžeme zoskupiť komponenty podľa konkrétnych kritérií - napríklad všetky triedy týkajúce sa vytrvalosti údajov - a skombinujte bloky tak, aby ste vytvorili výsledný kontajner:

val jdbcModule = Kodein.Module {bind () so singletonom {JdbcDao ()}} val kodein = Kodein {import (jdbcModule) bind () so singletom {Controller (instance ())} bind () so singletonom {Service (instance ( ), "myService")}} val dao: Dao = kodein.instance () assertThat (dao) .isInstanceOf (JdbcDao :: class.java)

Poznámka: pretože moduly obsahujú pravidlá viazania, cieľové fazule sa znovu vytvoria, keď sa ten istý modul použije vo viacerých inštanciách Kodein.

5.2. Zloženie

Môžeme rozšíriť jednu inštanciu Kodein z druhej - to nám umožní znovu použiť fazuľa:

val persistenceContainer = Kodein {bind () so singletonom {MongoDao ()}} val serviceContainer = Kodein {extend (persistenceContainer) bind () s singleton {Service (instance (), "myService")}} val fromPersistence: Dao = persistenceContainer. instance () val fromService: Dao = serviceContainer.instance () assertThat (fromPersistence) .isSameAs (fromService)

5.3. Naliehavé

Viazania môžeme prepísať - to môže byť užitočné pri testovaní:

trieda InMemoryDao: Dao val commonModule = Kodein.Module {bind () so singletonom {MongoDao ()} bind () s singleton {Service (instance (), "myService")}} val testContainer = Kodein {import (commonModule) bind ( overrides = true) s singleton {InMemoryDao ()}} val dao: Dao = testContainer.instance () assertThat (dao) .isInstanceOf (InMemoryDao :: class.java)

6. Viacväzby

Môžeme nakonfigurovať viac ako jedna fazuľa rovnakého spoločného (super-) typu v kontajneri:

val kodein = Kodein {bind () from setBinding () bind (). inSet () with singleton {MongoDao ()} bind (). inSet () with singleton {JdbcDao ()}} val daos: Set = kodein.instance ( ) assertThat (daos.map {it.javaClass as Class}) .containsOnly (MongoDao :: class.java, JdbcDao :: class.java)

7. Injektor

Náš kód aplikácie nevedel o Kodeine vo všetkých príkladoch, ktoré sme používali predtým - používal bežné argumenty konštruktora, ktoré boli poskytnuté počas inicializácie kontajnera.

Rámec to však umožňuje - alternatívny spôsob konfigurácie závislostí prostredníctvom delegovaných vlastností a Injektory:

trieda Controller2 {private val injector = KodeinInjector () val služba: Service by injector.instance () fun injectDependencies (kodein: Kodein) = injector.inject (kodein)} val kodein = Kodein {bind () with singleton {MongoDao ()} bind () s singleton {Service (instance (), "myService")}} val controller = Controller2 () controller.injectDependencies (kodein) assertThat (controller.service) .isNotNull

Inými slovami, doménová trieda definuje závislosti prostredníctvom injektora a získava ich z daného kontajnera. Takýto prístup je užitočný v konkrétnych prostrediach, ako je Android.

8. Používanie Kodeinu so systémom Android

V systéme Android je kontajner Kodein nakonfigurovaný ako obyčajný Aplikácia triedy a neskôr sa viaže na Kontext inštancia. Predpokladá sa, že všetky komponenty (aktivity, fragmenty, služby, rozhlasové prijímače) sú rozšírené z tried nástrojov, ako sú KodeinActivity a KodeinFragment:

trieda MyActivity: Activity (), KodeinInjected {override val injector = KodeinInjector () val random: Random by instance () override fun onCreate (savedInstanceState: Bundle?) {inject (appKodein ())}}

9. Analýza

V tejto časti uvidíme, ako si Kodein porovnáva s populárnymi DI frameworkmi.

9.1. Jarný rámec

Jarný rámec je oveľa bohatší na funkcie ako Kodein. Napríklad jar má veľmi pohodlné skenovanie komponentov. Keď označíme naše triedy konkrétnymi anotáciami ako @ Komponent, @Službaa @ Menovaný, skenovanie komponentov automaticky vyzdvihne tieto triedy počas inicializácie kontajnera.

Jar má tiež výkonné body rozšírenia metaprogramovania, BeanPostProcessor a BeanFactoryPostProcessor, čo môže byť rozhodujúce pri prispôsobovaní nakonfigurovanej aplikácie konkrétnemu prostrediu.

Nakoniec Spring poskytuje niektoré z nich na tom postavené pohodlné technológie, vrátane AOP, transakcií, testovacieho rámca a mnohých ďalších. Ak ich chceme použiť, stojí za to zostať pri kontajneri Spring IoC.

9.2. Dýka 2

Rámec Dagger 2 je nie tak bohatý na funkcie ako Spring Framework, ale je populárny vo vývoji systému Android kvôli svojej rýchlosti (generuje kód Java, ktorý vykonáva vstrekovanie a iba ho vykonáva za behu) a veľkosti.

Porovnajme počty a veľkosti metód knižníc:

Kodein:Všimnite si, že kotlin-stdlib závislosť predstavuje väčšinu týchto čísel. Keď to vylúčime, dostaneme 1282 metód a veľkosť DEX 244 KB.

Dýka 2:

Vidíme, že rámec Dagger 2 pridáva oveľa menej metód a jeho súbor JAR je menší.

Pokiaľ ide o použitie - je to veľmi podobné v tom, že používateľský kód konfiguruje závislosti (prostredníctvom Injektor v anotáciách Kodein a JSR-330 v Dagger 2) a neskôr ich injektuje prostredníctvom jedného volania metódy.

Kľúčovou vlastnosťou hry Dagger 2 je však to, že je overuje závislostný graf v čase kompilácie, takže neumožní kompiláciu aplikácie, ak dôjde k chybe konfigurácie.

10. Záver

Teraz vieme, ako používať Kodein na vkladanie závislostí, aké možnosti konfigurácie poskytuje a ako je v porovnaní s niekoľkými ďalšími populárnymi rámcami DI. Je však na vašom rozhodnutí, či ho použijete v reálnych projektoch.

Zdrojový kód vyššie uvedených vzorov nájdete ako vždy na serveri GitHub.


$config[zx-auto] not found$config[zx-overlay] not found