Injekcija ovisnosti Kotlina s Kodeinom

1. Pregled

U ovom ćemo članku predstaviti Kodein - čisti okvir za ubrizgavanje ovisnosti Kotlina (DI) - i usporediti ga s drugim popularnim DI okvirima.

2. Ovisnost

Prvo, dodajmo ovisnost Kodein na našu pom.xml:

 com.github.salomonbrys.kodein kodein 4.1.0 

Napominjemo da je najnovija dostupna verzija dostupna na Maven Central ili jCenter.

3. Konfiguracija

Za ilustraciju konfiguracije temeljene na Kodeinu poslužit ćemo se donjim modelom:

class Controller (private val service: Service) class Service (private val dao: Dao, private val tag: String) sučelje Dao class JdbcDao: Dao class MongoDao: Dao

4. Vrste vezivanja

Kodein framework nudi razne vrste veza. Pogledajmo bliže kako djeluju i kako ih koristiti.

4.1. Singleton

S Singleton obvezujući, ciljni grah je lijeno prikazan pri prvom pristupu i ponovno se koristi na svim daljnjim zahtjevima:

var stvoreno = netačno; val kodein = Kodein {veza () s jednostrukim {MongoDao ()}} assertThat (stvoren) .isFalse () val dao1: Dao = kodein.instance () assertThat (stvoren) .isFalse () val dao2: Dao = kodein.instance () assertThat (dao1) .isSameAs (dao2)

Napomena: možemo koristiti Kodein.instance () za dohvaćanje ciljano upravljanih grahova na temelju tipa statičke varijable.

4.2. Nestrpljivi Singleton

Ovo je slično Singleton vezivanje. Jedina je razlika u tome blok inicijalizacije poziva se nestrpljivo:

var stvoreno = netačno; val kodein = Kodein {bind () s jednostrukim {MongoDao ()}} assertThat (stvoren) .isTrue () val dao1: Dao = kodein.instance () val dao2: Dao = kodein.instance () assertThat (dao1) .isSameAs (dao2)

4.3. Tvornica

S Tvornica vezanje, blok inicijalizacije prima argument i iz njega se svaki put vrati novi objekt:

val kodein = Kodein {bind () s jednostrukim {MongoDao ()} bind () s tvornicom {tag: String -> Service (instance (), tag)}} val service1: Service = kodein.with ("myTag"). instance () val service2: Service = kodein.with ("myTag"). instance () assertThat (service1) .isNotSameAs (service2)

Napomena: možemo koristiti Kodein.instance () za konfiguriranje prijelaznih ovisnosti.

4.4. Multiton

Multiton vezivanje je vrlo slično Tvornica vezivanje. Jedina je razlika u tome isti objekt se vraća za isti argument u sljedećim pozivima:

val kodein = Kodein {bind () s jednostrukim {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. Pružatelj usluga

Ovo nije argument Tvornica obvezujući:

val kodein = Kodein {bind () s dobavljačem {MongoDao ()}} val dao1: Dao = kodein.instance () val dao2: Dao = kodein.instance () assertThat (dao1) .isNotSameAs (dao2)

4.6. Primjer

Možemo registrirati unaprijed konfiguriranu instancu graha u spremniku:

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

4.7. Označavanje

Možemo i mi registrirati više graha iste vrste pod različitim oznakama:

val kodein = Kodein {vezanje ("dao1") s jednostrukim {MongoDao ()} vezivanje ("dao2") s jednobojnim {MongoDao ()}} val dao1: Dao = kodein.instance ("dao1") val dao2: Dao = kodein.instance ("dao2") assertThat (dao1) .isNotSameAs (dao2)

4.8. Konstantno

Ovo je sintaktički šećer u odnosu na označeno vezanje i pretpostavlja se da se koristi za konstante konfiguracije - jednostavni tipovi bez nasljeđivanja:

val kodein = Kodein {konstanta ("magija") sa 42} val fromContainer: Int = kodein.instance ("magic") assertThat (fromContainer) .isEqualTo (42)

5. Odvajanje vezova

Kodein nam omogućuje da grah konfiguriramo u zasebne blokove i kombiniramo ih.

5.1. Moduli

Možemo grupirati komponente prema određenim kriterijima - na primjer, sve klase povezane s postojanošću podataka - i kombinirajte blokove za izgradnju rezultirajućeg spremnika:

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

Napomena: kako moduli sadrže pravila vezanja, ciljni grah se ponovno kreira kada se isti modul koristi u više Kodein instanci.

5.2. Sastav

Možemo proširiti jednu instancu Kodein iz druge - to nam omogućuje ponovnu upotrebu graha:

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

5.3. Nadjačavanje

Možemo nadjačati veze - ovo može biti korisno za testiranje:

klasa InMemoryDao: Dao val commonModule = Kodein.Module {bind () s jednokrilnim {MongoDao ()} bind () s jednobojnim {Service (instance (), "myService")}} val testContainer = Kodein {import (commonModule) bind ( zamjenjuje = true) s jednostrukim {InMemoryDao ()}} val dao: Dao = testContainer.instance () assertThat (dao) .isInstanceOf (InMemoryDao :: class.java)

6. Viševezični

Možemo konfigurirati više graha s istim zajedničkim (super) tipom u spremniku:

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

7. Injektor

Naš kod aplikacije nije bio svjestan Kodeina u svim primjerima koje smo prije koristili - koristio je redovite argumente konstruktora koji su pruženi tijekom inicijalizacije spremnika.

Međutim, okvir dopušta alternativni način konfiguriranja ovisnosti putem delegiranih svojstava i Injektori:

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

Drugim riječima, klasa domene definira ovisnosti putem injektora i dohvaća ih iz određenog spremnika. Takav je pristup koristan u specifičnim okruženjima poput Androida.

8. Korištenje Kodeina s Androidom

U Androidu je spremnik Kodein prilagođen Primjena razreda, a kasnije je vezan za Kontekst primjer. Pretpostavlja se da su sve komponente (aktivnosti, fragmenti, usluge, emitirani prijamnici) proširene iz klasa uslužnih programa poput KodeinActivity i KodeinFragment:

klasa MyActivity: Activity (), KodeinInjected {override val injector = KodeinInjector () val random: Random by instance () nadjačati zabavu naCreate (savedInstanceState: Bundle?) {inject (appKodein ())}}

9. Analiza

U ovom ćemo odjeljku vidjeti kako se Kodein uspoređuje s popularnim DI okvirima.

9.1. Proljetni okvir

Spring Framework mnogo je bogatiji značajkama od Kodeina. Na primjer, Proljeće ima vrlo prikladno sredstvo za skeniranje komponenata. Kada svoje razrede označimo određenim bilješkama poput @Komponenta, @Servis, i @Name, skeniranje komponenata automatski preuzima te klase tijekom inicijalizacije spremnika.

Proljeće također ima snažne produžne točke za meta-programiranje, BeanPostProcessor i BeanFactoryPostProcessor, što bi moglo biti presudno pri prilagođavanju konfigurirane aplikacije određenom okruženju.

Napokon, proljeće pruža neke prikladne tehnologije izgrađene na vrhu, uključujući AOP, transakcije, testni okvir i mnoge druge. Ako ih želimo koristiti, vrijedi se držati Spring IoC spremnika.

9.2. Bodež 2

Dagger 2 okvir je nije tako bogat značajkama kao Spring Framework, ali popularan je u razvoju Androida zbog brzine (generira Java kôd koji izvršava ubrizgavanje i samo ga izvršava u vrijeme izvođenja) i veličine.

Usporedimo brojeve i veličine metoda knjižnica:

Kodein:Imajte na umu da kotlin-stdlib ovisnost čini glavninu tih brojeva. Kad ga izuzmemo, dobit ćemo 1282 metode i 244 KB DEX veličine.

Bodež 2:

Vidimo da Dagger 2 okvir dodaje mnogo manje metoda, a njegova JAR datoteka je manja.

Što se tiče upotrebe - vrlo je slično po tome što korisnički kod konfigurira ovisnosti (kroz Injektor u bilješkama Kodein i JSR-330 u Daggeru 2) i kasnije ih ubrizgava jednim pozivom metode.

Međutim, ključna značajka Dagger 2 je ta provjerava graf ovisnosti u vrijeme sastavljanja, tako da neće dopustiti aplikaciji da se prevede ako postoji pogreška u konfiguraciji.

10. Zaključak

Sada znamo kako koristiti Kodein za ubrizgavanje ovisnosti, koje mogućnosti konfiguracije pruža i kako se uspoređuje s nekoliko drugih popularnih DI okvira. Međutim, na vama je da odlučite hoćete li ga koristiti u stvarnim projektima.

Kao i uvijek, izvorni kod za gornje uzorke možete pronaći na GitHubu.


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