Dagger2使用

為什么使用Dagger2

無(wú)論是構(gòu)造函數(shù)注入還是接口注入,都避免不了要編寫大量的模板代碼培漏。機(jī)智的猿猿們當(dāng)然不開(kāi)心做這些重復(fù)性的工作溪厘,于是各種依賴注入框架應(yīng)用而生胡本。但是這么多的依賴注入框架為什么我們卻偏愛(ài)Dagger2呢牌柄?我們先從Spring中的控制反轉(zhuǎn)(IOC)說(shuō)起。

談起依賴注入侧甫,做過(guò)J2EE開(kāi)發(fā)的同學(xué)一定會(huì)想起Spring IOC珊佣,那通過(guò)迷之XML來(lái)配置依賴的方式真的很讓人討厭;而且XML與Java代碼分離也導(dǎo)致代碼鏈難以追蹤披粟。之后更加先進(jìn)的Guice(Android端也有個(gè)RoboGuice)出現(xiàn)了咒锻,我們不再需要通過(guò)XML來(lái)配置依賴,但其運(yùn)行時(shí)實(shí)現(xiàn)注入的方式讓我們?cè)谧粉櫤投ㄎ诲e(cuò)誤的時(shí)候卻又萬(wàn)分痛苦守屉。開(kāi)篇提到過(guò)Dagger就是受Guice的啟發(fā)而開(kāi)發(fā)出來(lái)的惑艇;Dagger繼承了前輩的思想,在性能又碾壓了它的前輩Guice拇泛,可謂是長(zhǎng)江后浪推前浪滨巴,前浪死在沙灘上。

又如開(kāi)篇我在簡(jiǎn)介中說(shuō)到的俺叭,Dagger是一種半靜態(tài)半運(yùn)行時(shí)的DI框架恭取,雖說(shuō)依賴注入是完全靜態(tài)的,但是生成有向無(wú)環(huán)圖(DAG)還是基于反射來(lái)實(shí)現(xiàn)熄守,這無(wú)論在大型的服務(wù)端應(yīng)用還是在Android應(yīng)用上都不是最優(yōu)方案蜈垮。升級(jí)版的Dagger2解決了這一問(wèn)題,從半靜態(tài)變?yōu)橥耆o態(tài)裕照,從Map式的API變成申明式API(@Module)攒发,生成的代碼更優(yōu)雅高效;而且一旦出錯(cuò)我們?cè)诰幾g期間就能發(fā)現(xiàn)晋南。所以Dagger2對(duì)開(kāi)發(fā)者的更加友好了惠猿,當(dāng)然Dagger2也因此喪失了一些靈活性,但總體來(lái)說(shuō)利還是遠(yuǎn)遠(yuǎn)大于弊的搬俊。

前面提到這種A B C D E連續(xù)依賴的問(wèn)題紊扬,一旦E的創(chuàng)建方式發(fā)生了改變就會(huì)引發(fā)連鎖反應(yīng)蜒茄,可能會(huì)導(dǎo)致A B C D都需要做針對(duì)性的修改;但是騷年餐屎,你以為為這僅僅是工作量的問(wèn)題嗎檀葛?更可怕的是我們創(chuàng)建A時(shí)需要按順序先創(chuàng)建E D C B四個(gè)對(duì)象,而且必須保證順序上是正確的腹缩。Dagger2就很好的解決了這一問(wèn)題(不只是Dagger2屿聋,在其他DI框架中開(kāi)發(fā)者同樣不需要關(guān)注這些問(wèn)題)。

Dagger2注解

開(kāi)篇我們就提到Dagger2是基于Java注解來(lái)實(shí)現(xiàn)依賴注入的藏鹊,那么在正式使用之前我們需要先了解下Dagger2中的注解润讥。Dagger2使用過(guò)程中我們通常接觸到的注解主要包括:@Inject, @Module, @Provides, @Component, @Qulifier, @Scope, @Singleten。

@Inject:@Inject有兩個(gè)作用盘寡,一是用來(lái)標(biāo)記需要依賴的變量楚殿,以此告訴Dagger2為它提供依賴;二是用來(lái)標(biāo)記構(gòu)造函數(shù)竿痰,Dagger2通過(guò)@Inject注解可以在需要這個(gè)類實(shí)例的時(shí)候來(lái)找到這個(gè)構(gòu)造函數(shù)并把相關(guān)實(shí)例構(gòu)造出來(lái)脆粥,以此來(lái)為被@Inject標(biāo)記了的變量提供依賴;

@Module:@Module用于標(biāo)注提供依賴的類影涉。你可能會(huì)有點(diǎn)困惑变隔,上面不是提到用@Inject標(biāo)記構(gòu)造函數(shù)就可以提供依賴了么,為什么還需要@Module蟹倾?很多時(shí)候我們需要提供依賴的構(gòu)造函數(shù)是第三方庫(kù)的匣缘,我們沒(méi)法給它加上@Inject注解,又比如說(shuō)提供以來(lái)的構(gòu)造函數(shù)是帶參數(shù)的鲜棠,如果我們之所簡(jiǎn)單的使用@Inject標(biāo)記它肌厨,那么他的參數(shù)又怎么來(lái)呢?@Module正是幫我們解決這些問(wèn)題的岔留。

@Provides:@Provides用于標(biāo)注Module所標(biāo)注的類中的方法夏哭,該方法在需要提供依賴時(shí)被調(diào)用,從而把預(yù)先提供好的對(duì)象當(dāng)做依賴給標(biāo)注了@Inject的變量賦值献联;

@Component:@Component用于標(biāo)注接口竖配,是依賴需求方和依賴提供方之間的橋梁。被Component標(biāo)注的接口在編譯時(shí)會(huì)生成該接口的實(shí)現(xiàn)類(如果@Component標(biāo)注的接口為CarComponent里逆,則編譯期生成的實(shí)現(xiàn)類為DaggerCarComponent),我們通過(guò)調(diào)用這個(gè)實(shí)現(xiàn)類的方法完成注入进胯;

@Qulifier:@Qulifier用于自定義注解,也就是說(shuō)@Qulifier就如同Java提供的幾種基本元注解一樣用來(lái)標(biāo)記注解類原押。我們?cè)谑褂聾Module來(lái)標(biāo)注提供依賴的方法時(shí)胁镐,方法名我們是可以隨便定義的(雖然我們定義方法名一般以provide開(kāi)頭,但這并不是強(qiáng)制的,只是為了增加可讀性而已)盯漂。那么Dagger2怎么知道這個(gè)方法是為誰(shuí)提供依賴呢颇玷?答案就是返回值的類型,Dagger2根據(jù)返回值的類型來(lái)決定為哪個(gè)被@Inject標(biāo)記了的變量賦值就缆。但是問(wèn)題來(lái)了帖渠,一旦有多個(gè)一樣的返回類型Dagger2就懵逼了。@Qulifier的存在正式為了解決這個(gè)問(wèn)題竭宰,我們使用@Qulifier來(lái)定義自己的注解空郊,然后通過(guò)自定義的注解去標(biāo)注提供依賴的方法和依賴需求方(也就是被@Inject標(biāo)注的變量),這樣Dagger2就知道為誰(shuí)提供依賴了切揭。----一個(gè)更為精簡(jiǎn)的定義:當(dāng)類型不足以鑒別一個(gè)依賴的時(shí)候狞甚,我們就可以使用這個(gè)注解標(biāo)示;

@Scope:@Scope同樣用于自定義注解廓旬,我能可以通過(guò)@Scope自定義的注解來(lái)限定注解作用域哼审,實(shí)現(xiàn)局部的單例;

@Singleton:@Singleton其實(shí)就是一個(gè)通過(guò)@Scope定義的注解嗤谚,我們一般通過(guò)它來(lái)實(shí)現(xiàn)全局單例棺蛛。但實(shí)際上它并不能提前全局單例,是否能提供全局單例還要取決于對(duì)應(yīng)的Component是否為一個(gè)全局對(duì)象巩步。

我們提到@Inject和@Module都可以提供依賴,那如果我們即在構(gòu)造函數(shù)上通過(guò)標(biāo)記@Inject提供依賴桦踊,有通過(guò)@Module提供依賴Dagger2會(huì)如何選擇呢椅野?具體規(guī)則如下:

步驟1:首先查找@Module標(biāo)注的類中是否存在提供依賴的方法。

步驟2:若存在提供依賴的方法籍胯,查看該方法是否存在參數(shù)竟闪。

a:若存在參數(shù),則按從步驟1開(kāi)始依次初始化每個(gè)參數(shù)杖狼;

b:若不存在炼蛤,則直接初始化該類實(shí)例,完成一次依賴注入蝶涩。

步驟3:若不存在提供依賴的方法理朋,則查找@Inject標(biāo)注的構(gòu)造函數(shù),看構(gòu)造函數(shù)是否存在參數(shù)绿聘。

a:若存在參數(shù)嗽上,則從步驟1開(kāi)始依次初始化每一個(gè)參數(shù)

b:若不存在,則直接初始化該類實(shí)例熄攘,完成一次依賴注入兽愤。

Dagger2注解@Module ,@Component,@Inject的關(guān)系

簡(jiǎn)單的說(shuō)浅萧,就是一個(gè)工廠模式逐沙,由Dagger負(fù)責(zé)創(chuàng)建工廠,幫忙生產(chǎn)instance洼畅。遵從Java規(guī)范JSR 330酱吝,可以使用這些注解。現(xiàn)在不研究Dagger2是如何根據(jù)注解去生成工廠的土思,先來(lái)看看工廠是什么東西务热,理解為什么可以實(shí)現(xiàn)了DI(Dependency Injection),如何創(chuàng)建IoC(Inverse of Control)容器己儒。

Dagger2是通過(guò)依賴注入完成類的初始化崎岂。

這個(gè)過(guò)程需要三部分:

#1****依賴提供方(生產(chǎn)者)

#2****依賴注入容器(橋梁)

#3****依賴需求方(消費(fèi)者)

image

總結(jié):

@Inject主要有兩個(gè)作用

#1作為依賴注提供方

使用@Inject注解構(gòu)造方法。

注解構(gòu)造函數(shù)闪湾,讓Dagger2幫我們實(shí)例化該冲甘,并注入。

#2作為依賴需求方:

使用@Inject注解成員途样。

如果一個(gè)成員變量被@Inject注解修飾江醇,并且成員類構(gòu)造函數(shù)也被@Inject注解,那么dagger2幫我們實(shí)例化該成員類何暇,并注入陶夜。

通常在需要依賴的地方使用這個(gè)注解。換句話說(shuō)裆站,你用它告訴Dagger這個(gè)類或者字段需要依賴注入条辟。這樣,Dagger就會(huì)構(gòu)造一個(gè)這個(gè)類的實(shí)例并滿足他們的依賴宏胯。

使用@Inject可以讓IoC容器負(fù)責(zé)生成instance羽嫡,如果沒(méi)有這個(gè)注解,dagger將不認(rèn)識(shí)肩袍,當(dāng)做普通類杭棵,無(wú)法代理

@Module的作用

#1@Module注解,負(fù)責(zé)管理依賴氛赐。

Module 其實(shí)是一個(gè)簡(jiǎn)單工廠模式魂爪,Module 里面的方法都是創(chuàng)建相應(yīng)類實(shí)例的方法。

#2通過(guò)@Module獲得第三方類庫(kù)的對(duì)象鹰祸。

#3@Module是一個(gè)依賴提供方的合集甫窟。

@ModulepublicclassAModule{@ProvidespublicGsonprovideGson(){returnnewGson();}}

@Provides

#1注解@Module中的方法

在modules中蛙婴,我們定義的方法是用這個(gè)注解粗井,以此來(lái)告訴Dagger我們想要構(gòu)造對(duì)象并提供這些依賴。

@Component的作用

#1@Component一般用來(lái)注解接口

#2負(fù)責(zé)在@Inject和@Module之間建立連接浇衬。

也可以說(shuō)是@Inject和@Module的橋梁懒构,它的主要作用就是連接這兩個(gè)部分。

#3實(shí)例化@Inject注解的時(shí)耘擂,遇到?jīng)]有構(gòu)造函數(shù)的類依賴胆剧,則該依賴由@Module修飾的類提供。

#4****依賴注入容器只是一個(gè)接口interface醉冤。

Component需要引用到目標(biāo)類的實(shí)例歌馍,Component會(huì)查找目標(biāo)類中用Inject注解標(biāo)注的屬性汞舱,查找到相應(yīng)的屬性后會(huì)接著查找該屬性對(duì)應(yīng)的用Inject標(biāo)注的構(gòu)造函數(shù)(這時(shí)候就發(fā)生聯(lián)系了)矮冬,剩下的工作就是初始化該屬性的實(shí)例并把實(shí)例進(jìn)行賦值宝穗。因此我們也可以給Component叫另外一個(gè)名字注入器(Injector)

Component注解的類,再編譯之后,會(huì)生產(chǎn)一個(gè)以Dagger+類名的一個(gè)類,如下面的MainComponent會(huì)生成類DaggerMainComponent(補(bǔ)充一點(diǎn),Kotlinkapt編譯生成類的位置:\build\generated\source\kapt\debug),我們需要在目標(biāo)類MainActivity中加入下面代碼

DaggerMainComponent.builder()

            .build()

            .inject(this)

DaggerMainComponent使用了建造者設(shè)計(jì)模式,inject方法是我們MainComponent中定義的,這樣目標(biāo)類就和Component建立了聯(lián)系.Component會(huì)去遍歷使用@Inject注解的常量,然后去查找對(duì)應(yīng)的類是否有@Inject注解的構(gòu)造方法,如果沒(méi)有就會(huì)報(bào)異常.

@Component{modules={HeaterModule.class,PumperModule.class}}publicinterfaceMachineComponent{voidinject(CoffeeMachine machine);}

dagger中Component就是最頂級(jí)的入口,dagger為之生成了工廠類 DaggerMachineComponent螺捐,目標(biāo)是構(gòu)建CoffeeMachine颠悬, 在CoffeeMachine中使用了Injection,那么依賴要由工廠類來(lái)提供定血。工廠類是根據(jù)modules的參數(shù)來(lái)找依賴綁定的赔癌。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市澜沟,隨后出現(xiàn)的幾起案子灾票,更是在濱河造成了極大的恐慌,老刑警劉巖倔喂,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铝条,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡席噩,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門贤壁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悼枢,“玉大人,你說(shuō)我怎么就攤上這事脾拆÷鳎” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵名船,是天一觀的道長(zhǎng)绰上。 經(jīng)常有香客問(wèn)我,道長(zhǎng)渠驼,這世上最難降的妖魔是什么蜈块? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上百揭,老公的妹妹穿的比我還像新娘爽哎。我一直安慰自己,他們只是感情好器一,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布课锌。 她就那樣靜靜地躺著,像睡著了一般祈秕。 火紅的嫁衣襯著肌膚如雪渺贤。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,457評(píng)論 1 311
  • 那天请毛,我揣著相機(jī)與錄音志鞍,去河邊找鬼。 笑死获印,一個(gè)胖子當(dāng)著我的面吹牛述雾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兼丰,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼玻孟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了鳍征?” 一聲冷哼從身側(cè)響起黍翎,我...
    開(kāi)封第一講書(shū)人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎艳丛,沒(méi)想到半個(gè)月后匣掸,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡氮双,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年碰酝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戴差。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡送爸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出暖释,到底是詐尸還是另有隱情袭厂,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布球匕,位于F島的核電站纹磺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏亮曹。R本人自食惡果不足惜橄杨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一秘症、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧讥珍,春花似錦历极、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至氏义,卻和暖如春锄列,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惯悠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工邻邮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人克婶。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓筒严,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親情萤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鸭蛙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360