Android:dagger2讓你愛不釋手-基礎依賴注入框架篇

前言

dagger2的大名我想大家都已經很熟了,它是解決Android或java中依賴注入的一個類庫(DI類庫)。當我看到一些開源的項目在使用dagger2時,我也有種匆匆欲動的感覺,因此就立馬想一探它的究竟,到底能給我帶來怎樣的好處。在學習使用dagger2的過程中,我遇到了以下的一些困惑:

  • dagger2中的Inject,Component,Module,Provides等等都是什麼東東,有什麼作用?
  • dagger2到底能帶來哪些好處?
  • 怎樣把dagger2應用到具體項目中?

在具體學習dagger2的時候,看了好多博客,看的時候感覺挺簡單的,但是在真正使用到項目中時候,腦袋就懵了,無從下手,Component應該怎麼用,能放些什麼方法? Module應該放些啥內容?Scope怎麼起到作用域控制?.....各種疑問就橫空而出。所以也許會有正在學習或即將要使用dagger2的同學在使用過程中遇到和我一樣的困惑,因此我決定把我對dagger2的理解、使用經驗分享給大家,希望能對大家有幫助。
我會分幾節給講解dagger2。

本節內容

Inject,Component,Module,Provides它們是什麼?怎麼去理解它們?各自有什麼作用?主要從抽象的概念講解,不會涉及到具體代碼的剖析。

提前科普知識點

在講解之前,我希望大家對以下知識點有所瞭解(知道的同學可以跳過)

  • 依賴注入(Dependency Injection簡稱DI)
  • java中註解(Annotation)

依賴注入:就是目標類(目標類需要進行依賴初始化的類,下面都會用目標類一詞來指代)中所依賴的其他的類的初始化過程,不是通過手動編碼的方式創建,而是通過技術手段可以把其他的類的已經初始化好的實例自動注入到目標類中。


di.png


若您還是對依賴注入不瞭解,點擊我可以讓您瞭解更多
dagger2就是實現依賴注入的一種技術手段

其次java註解的概念用法我們就不講了,dagger2中核心點就是java註解,點擊我可以瞭解更多java註解知識

正式開始

以下的內容我會嘗試着去模仿dagger2的作者是怎樣一步步完成dagger2這樣偉大的依賴注入類庫的場景來講解(首先這個場景是我意淫的,大家勿噴,模仿該場景主要目的是爲了能由簡到難一步步更深入的瞭解dagger2)

Inject是什麼鬼

先看一段代碼:

 class A{
       B b = new B(...);
       C c = new C();
       D d = new D(new E());
       F f = new F(.....);
 }

上面的代碼完全沒任何問題,但是總感覺創建對象的這些代碼基本都是重複的體力勞動,那何嘗不想個辦法,把這些重複的體力勞動用一種自動化的、更省力的方法解決掉,這樣就可以讓開發的效率提高,可以把精力集中在重要的業務上了。

我們可以用註解(Annotation)來標註目標類中所依賴的其他類,同樣用註解來標註所依賴的其他類的構造函數,那註解的名字就叫Inject

   class A{
        @Inject
        B b;
   }

   class B{
       @Inject
       B(){
       }
   }

這樣我們就可以讓目標類中所依賴的其他類與其他類的構造函數之間有了一種無形的聯繫。但是要想使它們之間產生直接的關係,還得需要一個橋樑來把它們之間連接起來。那這個橋樑就是Component了。


Inject.png

Component又是什麼鬼
Component也是一個註解類,一個類要想是Component,必須用Component註解來標註該類,並且該類是接口或抽象類。我們不討論具體類的代碼,我想從抽象概念的角度來討論Component。上文中提到Component在目標類中所依賴的其他類與其他類的構造函數之間可以起到一個橋樑的作用。
那我們看看這橋樑是怎麼工作的:
Component需要引用到目標類的實例,Component會查找目標類中用Inject註解標註的屬性,查找到相應的屬性後會接着查找該屬性對應的用Inject標註的構造函數(這時候就發生聯繫了),剩下的工作就是初始化該屬性的實例並把實例進行賦值。因此我們也可以給Component叫另外一個名字注入器(Injector)


component.png


小結下
目標類想要初始化自己依賴的其他類:

  • 用Inject註解標註目標類中其他類
  • 用Inject註解標註其他類的構造函數
  • 若其他類還依賴於其他的類,則重複進行上面2個步驟
  • 調用Component(注入器)的injectXXX(Object)方法開始注入(injectXXX方法名字是官方推薦的名字,以inject開始)

Component現在是一個注入器,就像注射器一樣,Component會把目標類依賴的實例注入到目標類中,來初始化目標類中的依賴。

爲啥又造出個Module

現在有個新問題:項目中使用到了第三方的類庫,第三方類庫又不能修改,所以根本不可能把Inject註解加入這些類中,這時我們的Inject就失效了。

那我們可以封裝第三方的類庫,封裝的代碼怎麼管理呢,總不能讓這些封裝的代碼散落在項目中的任何地方,總得有個好的管理機制,那Module就可以擔當此任。
可以把封裝第三方類庫的代碼放入Module中,像下面的例子:

    @Module
    public class ModuleClass{
          //A是第三方類庫中的一個類
          A provideA(){
               return A();
          }
    }

Module其實是一個簡單工廠模式,Module裏面的方法基本都是創建類實例的方法。接下來問題來了,因爲Component是注入器(Injector),我們怎麼能讓Component與Module有聯繫呢?

Component的新職責

Component是注入器,它一端連接目標類,另一端連接目標類依賴實例,它把目標類依賴實例注入到目標類中。上文中的Module是一個提供類實例的類,所以Module應該是屬於Component的實例端的(連接各種目標類依賴實例的端),Component的新職責就是管理好Module,Component中的modules屬性可以把Module加入Component,modules可以加入多個Module。


Component_橋樑概念.png

那接下來的問題是怎麼把Module中的各種創建類的實例方法與目標類中的用Inject註解標註的依賴產生關聯,那Provides註解就該登場了。

Provides最終解決第三方類庫依賴注入問題

Module中的創建類實例方法用Provides進行標註,Component在搜索到目標類中用Inject註解標註的屬性後,Component就會去Module中去查找用Provides標註的對應的創建類實例方法,這樣就可以解決第三方類庫用dagger2實現依賴注入了。

總結

Inject,Component,Module,Provides是dagger2中的最基礎最核心的知識點。奠定了dagger2的整個依賴注入框架

  • Inject主要是用來標註目標類的依賴和依賴的構造函數
  • Component它是一個橋樑,一端是目標類,另一端是目標類所依賴類的實例,它也是注入器(Injector)負責把目標類所依賴類的實例注入到目標類中,同時它也管理Module。
  • Module和Provides是爲解決第三方類庫而生的,Module是一個簡單工廠模式,Module可以包含創建類實例的方法,這些方法用Provides來標註

component_module_inject.png


希望能幫您更好的理解dagger2。



文/牛曉偉(簡書作者)
原文鏈接:http://www.jianshu.com/p/cd2c1c9f68d4
著作權歸作者所有,轉載請聯繫作者獲得授權,並標註“簡書作者”。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章