dagger2的使用和優(yōu)缺點(diǎn)分析

前言

最近在做技術(shù)通道代碼評(píng)審時(shí),發(fā)現(xiàn)騰訊挺多項(xiàng)目有使用比較“老”的dagger2框架,自己也是幾年前在上家公司使用過,具體使用和原理都有點(diǎn)模糊了,完全不好評(píng)判評(píng)審代碼優(yōu)劣。 但是明確記得jectpack的hilt 是基于dagger2優(yōu)化的。也私聊了部分開發(fā)同學(xué),為什么不使用更好用的hilt,得到的答復(fù)基本都是歷史代碼為了統(tǒng)一代碼風(fēng)格。在review代碼時(shí)候發(fā)現(xiàn)依賴注入看起來比較亂,并沒有看出啥獨(dú)到之處。為了更好的評(píng)審代碼,抽空補(bǔ)補(bǔ)dagger2發(fā)現(xiàn)這個(gè)框架還是挺有意義的。

下面分3個(gè)部分介紹dagger2, 分別介紹他的基本使用和框架實(shí)現(xiàn)原理以及熟悉dagger2框架實(shí)現(xiàn)意義以及自己在學(xué)習(xí)該框架的一些思考總結(jié)

1.基本的使用

dagger2出現(xiàn)的背景:
比如項(xiàng)目中有一個(gè)全局到處都用到的對(duì)象,以我們項(xiàng)目舉例股票對(duì)象:Stock 假如我要改動(dòng)Stock對(duì)象的默認(rèn)無參構(gòu)造為每個(gè)地方都要給他傳一個(gè)參數(shù)進(jìn)去 而這個(gè)Stock對(duì)象在整個(gè)項(xiàng)目成百上千個(gè)地方都直接new Stock(),有這種改動(dòng)時(shí) 需要全部替換為new Stock("參數(shù)")。當(dāng)然我們可以全局搜索替換。不糾結(jié)這個(gè) 想表達(dá)的就是創(chuàng)建對(duì)象在各個(gè)地方都是new的,耦合比較嚴(yán)重,dagger2就是為了解決這種耦合,把new的過程通過APT在編譯階段生成代碼,我們只需要通過注解標(biāo)識(shí),自動(dòng)幫我們new出來,這樣我們不用去改成百上千的地方,只需要改一個(gè)地方就行

上面的背景介紹完,你可能會(huì)想到這和網(wǎng)絡(luò)請(qǐng)求封裝中間層一樣嗎?到處都直接使用volley網(wǎng)絡(luò)框架,后面要升級(jí)到okhttp每個(gè)地方都要替換,如果有個(gè)中間層,直接替換中間層的實(shí)現(xiàn)就好一樣樣的。
1.1 引入依賴:
implementation 'com.google.dagger:dagger:2.4'
annotationProcessor 'com.google.dagger:dagger-compiler:2.4'

dagger2的使用主要涉及4個(gè)對(duì)象:對(duì)象、module、 component、inject

1.2 對(duì)象定義:

對(duì)象就一個(gè)簡(jiǎn)單的股票對(duì)象就行:

public class StockObject {}
1.3 封裝module:

使用module和Provides注解,提供對(duì)象時(shí)創(chuàng)建股票對(duì)象:

@Module
public class StockModule {

    @Provides
    public StockObject providerStockObject(){
        return new StockObject();
    }
}

1.4 定義component:

組件使用接口,通過component注解指定module:

@Component(modules = {StockModule.class, BrokersModule.class})
public interface TestComponent {

    void injectMainActivity2(MainActivity2 activity2);
}
1.5 調(diào)用注入代碼:

使用注入的注解來標(biāo)識(shí)要注入的對(duì)象,然后編譯后的component調(diào)用注入方法,這個(gè)時(shí)候?qū)ο笠呀?jīng)被創(chuàng)建了:

  @Inject
  StockObject stock;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        // 方式一
        DaggerTestComponent.create().injectMainActivity2(this);
        Log.i("測(cè)試", stock.hashCode() + " MainActivity2");
    }

2.實(shí)現(xiàn)原理

從上面幾個(gè)步驟的使用可以看出主要使用了APT技術(shù),通過不同的注解,在編譯時(shí)生成一些輔類,從1.1的注解處理工具也可以看出實(shí)現(xiàn)原理
我們可以看下編譯后生成的類如下:


image.png
2.1源碼查看入口
DaggerTestComponent.create().injectMainActivity2(this);

我們代碼里直接在activity調(diào)用生成的component的注入方法,有個(gè)共性提前說下,生成的代碼大部分都提供了create方法,里面其實(shí)就創(chuàng)建了生成類對(duì)象。
直接上圖,關(guān)鍵流程步驟都標(biāo)注好了,


image.png

走到上面第9步,再看下provider的get方法,實(shí)現(xiàn)在生成的Factory里面,刪除無用代碼,主要調(diào)用 module.providerStockObject() 這個(gè)就是我們自己寫的module中創(chuàng)建的真實(shí)的對(duì)象:

public final class StockModule_ProviderStockObjectFactory implements Factory<StockObject> {
  private final StockModule module;

  @Override
  public StockObject get() {
    return Preconditions.checkNotNull(
        module.providerStockObject(), "Cannot return null from a non-@Nullable @Provides method");
  }
}

上面就是整個(gè)注入的源碼實(shí)現(xiàn),還是比較清晰的
1.在初始化時(shí),生成組件內(nèi)部通過建造者模式創(chuàng)建了module對(duì)象,調(diào)用工廠類傳入module生成provider,再把provider給到注入器
2.在使用頁面調(diào)用生成組件注入當(dāng)前activity
3.調(diào)用注入器的注入成員方法,獲取當(dāng)前activity的注入成員,使用provider的get賦值
4.在provider中,直接獲取module的具體提供對(duì)象,也就是真實(shí)的對(duì)象

3.意義和思考(總結(jié))

有意義的地方是:
1.可以拓展自己的技術(shù)面,不然看不懂別人的代碼無法裝逼
2.dagger的設(shè)計(jì)初衷是解耦合,但是實(shí)際使用比較比較難用。如果只是為了不改多個(gè)地方實(shí)際可以做一個(gè)封裝,類似他源碼實(shí)現(xiàn)用工廠模式、中間層 代理等方式來簡(jiǎn)化。
3.里面比較亮點(diǎn)的地方反而是他的注解處理實(shí)現(xiàn),開發(fā)者只需要關(guān)注注解使用。和Arouter比較類似,主要目的是簡(jiǎn)化開發(fā)使用,通過APT生成一些幫助類,業(yè)務(wù)開發(fā)不需要關(guān)注具體實(shí)現(xiàn),來實(shí)現(xiàn)解耦的目的。在架構(gòu)和封裝角度看 還是值得學(xué)習(xí)的。

總結(jié):
dagger2框架主要是通過注解方式實(shí)現(xiàn)依賴注入,調(diào)用地方不用自己new 對(duì)象,通過APT在編譯時(shí)候生成代碼實(shí)現(xiàn)幫助new對(duì)象功能,實(shí)現(xiàn)解耦。里面涉及基本的對(duì)象、module、component、注入四個(gè)大的模塊。module里面封裝真實(shí)的對(duì)象,然后給到組件,組件根據(jù)誰注入的幫調(diào)用注入的傳遞基本的對(duì)象。類比在家下單點(diǎn)外賣,外賣員把外賣送到家一樣??觳途褪腔緦?duì)象,module就是包裝盒,provider就是袋子,外賣員就是component,用戶點(diǎn)餐就是注入門牌號(hào)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容