Dagger依賴注入詳解(二)

系列文章第一篇:
http://www.reibang.com/p/33b739bd721a

  1. 概述
    上一期我們已經(jīng)對Dagger的基本概念以及結(jié)構(gòu)做了介紹活逆。那么現(xiàn)在我們將對Dagger作深入探究,了解它究竟是怎么實(shí)現(xiàn)自動(dòng)注入的驼侠,它在我們引用注解后做了哪些工作教硫。

  2. 探究
    2.1 思路
    在古代涧尿,人們選擇靠近水源的地點(diǎn)作為聚居地百新,很大一部分原因是我們需要水來灌溉莊稼帖蔓。我們可以把步驟大概簡化為:水源(提供水)——水車(獲取水)——導(dǎo)管(引流)——農(nóng)田矮瘟。其實(shí)Dagger注入也是遵循這個(gè)過程,下面我們按照這個(gè)思路對dagger進(jìn)行剖析塑娇。
    上篇我們說過澈侠,Module是專門提供依賴的,可以看作水源埋酬;Component是注入器哨啃,我們可以把它看成水車烧栋;Inject是被注入的對象,是農(nóng)田和莊稼拳球。
    2.2 Module
    在探究Module之前我們首先了解一下Module類的寫法:

@Module
public class ApplicationModule {

    private final AndroidApplication mApplication;
    private final DaoSession mDaoSession;
    private final RxBus mRxBus;

    public ApplicationModule(AndroidApplication application, DaoSession daoSession, RxBus rxBus) {
        mApplication = application;
        mDaoSession = daoSession;
        mRxBus = rxBus;
    }

    @Provides
    @Singleton
    Context provideApplicationContext() {
        return mApplication.getApplication();
    }

    @Provides
    @Singleton
    RxBus provideRxBus() {
        return mRxBus;
    }

    @Provides
    @Singleton
    DaoSession provideDaoSession() {
        return mDaoSession;
    }
}

@Providers表示此處會(huì)提供依賴审姓,而@Singleton表示提供的依賴對象將是單例形式。
好的祝峻,我們現(xiàn)在已經(jīng)有了依賴提供者魔吐,就相當(dāng)于有了一個(gè)農(nóng)民伯伯為莊稼找到了水源,現(xiàn)在我們需要想辦法將水源導(dǎo)出來莱找,注入到種莊稼的田地里酬姆,也就是我們需要有一個(gè)踩水車,而我們的Component則是負(fù)責(zé)踩水車這個(gè)角色奥溺。
2.3 Component
首先我們看下Component類

@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
    Context getContext();
    RxBus getRxBus();
    DaoSession getDaoSession();
}

我們這里定義的是ApplicationComponent辞色,我們在自己的Application類中實(shí)例化:

public App extends Applicaion{
      private static ApplicationComponent sAppComponent;
    ...//省略
      @Override
      public void onCreate() {
          super.onCreate();
          initConfig();
      }
     ...//省略
      private void initInjector() {
          sAppComponent = DaggerApplicationComponent.builder()
                  .applicationModule(new ApplicationModule(this, mDaoSession, mRxBus))
                  .build();
      }
     ...//省略
}

這里Dagger會(huì)根據(jù)相應(yīng)的注解自動(dòng)使用apt在/app/build/generated/apt/debug/中生成對應(yīng)的DaggerApplicationComponent類。我們觀察一下該類浮定,也就是看下水車的結(jié)構(gòu)相满。

public final class DaggerApplicationComponent implements ApplicationComponent {
  private Provider<Context> provideApplicationContextProvider;

  private Provider<RxBus> provideRxBusProvider;

  private Provider<DaoSession> provideDaoSessionProvider;

  private DaggerApplicationComponent(Builder builder) {
    assert builder != null;
    initialize(builder);
  }

  public static Builder builder() {
    return new Builder();
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.provideApplicationContextProvider =
        DoubleCheck.provider(
            ApplicationModule_ProvideApplicationContextFactory.create(builder.applicationModule));

    this.provideRxBusProvider =
        DoubleCheck.provider(
            ApplicationModule_ProvideRxBusFactory.create(builder.applicationModule));

    this.provideDaoSessionProvider =
        DoubleCheck.provider(
            ApplicationModule_ProvideDaoSessionFactory.create(builder.applicationModule));
  }

  @Override
  public Context getContext() {
    return provideApplicationContextProvider.get();
  }

  @Override
  public RxBus getRxBus() {
    return provideRxBusProvider.get();
  }

  @Override
  public DaoSession getDaoSession() {
    return provideDaoSessionProvider.get();
  }

  public static final class Builder {
    private ApplicationModule applicationModule;

    private Builder() {}

    public ApplicationComponent build() {
      if (applicationModule == null) {
        throw new IllegalStateException(
            ApplicationModule.class.getCanonicalName() + " must be set");
      }
      return new DaggerApplicationComponent(this);
    }

    public Builder applicationModule(ApplicationModule applicationModule) {
      this.applicationModule = Preconditions.checkNotNull(applicationModule);
      return this;
    }
  }
}

代碼不多,但是比較混雜壶唤,我們慢慢擼:
我們觀察到Dagger使用在生成相應(yīng)的DaggerApplicationComponent 類時(shí)采用了建造者模式雳灵,其構(gòu)造方法私有意味著并不能直接new出來,而是需要通過建造者類Builder闸盔。而Builder類是DaggerApplicationComponent 中的公共靜態(tài)內(nèi)部類悯辙,其構(gòu)造方法中會(huì)傳入ApplicationModule 并持有它。
那么這樣就清楚了迎吵,首先我們通過建造者類將ApplicationModule 傳入并持有引用躲撰,其次將建造者類作為DaggerApplicationComponent 構(gòu)造方法的參數(shù)傳入DaggerApplicationComponent 類中,這樣DaggerApplicationComponent 就持有了ApplicationModule 击费,也就是持有了依賴提供者拢蛋。這時(shí)候我們可以理解為我們成功建造了水車,并且接入了水源蔫巩。
現(xiàn)在我們仔細(xì)分析一下DaggerApplicationComponent 類谆棱。
首先Dagger獲取被@Providers注解的方法的返回值,使用Provider結(jié)構(gòu)包裹返回值圆仔,生成相應(yīng)的Provider的私有字段垃瞧,然后在initialize方法中,拿到建造者類Builder中持有的applicationModule坪郭。
于此同時(shí)在/app/build/generated/apt/debug/生成被@Providers注解方法的返回值的對應(yīng)的工廠類个从,例如ApplicationModule_ProvideApplicationContextFactory。
我們順著工廠類看下去:

public final class ApplicationModule_ProvideApplicationContextFactory implements Factory<Context> {
  private final ApplicationModule module;

  public ApplicationModule_ProvideApplicationContextFactory(ApplicationModule module) {
    assert module != null;
    this.module = module;
  }

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

  public static Factory<Context> create(ApplicationModule module) {
    return new ApplicationModule_ProvideApplicationContextFactory(module);
  }
}

我們看到工廠類實(shí)現(xiàn)了Factory<T>接口,其實(shí)在深入一層的話嗦锐,我們會(huì)發(fā)現(xiàn)Factory是繼承自Provider接口的嫌松,所以Factory實(shí)際上也是提供者,使用Factory的原因在于利于更好的拓展性。在Factory中傳入相應(yīng)的module奕污,并在get方法中拿取到被@Provider注解的方法返回的具體的對象(詳見:module.provideApplicationContext())萎羔。
我們繼續(xù)返回上層的DaggerApplicationComponent 的initialize方法。我們發(fā)現(xiàn)從工廠類中獲取的對象直接就賦值給了相應(yīng)的Provider字段菊值。
至此外驱,DaggerApplicationComponent 實(shí)現(xiàn)了獲取ApplicationModule中被@Provider注解的相應(yīng)方法的返回對象并使用Provider持有該對象DaggerApplicationComponent 重寫ApplicationComponent 的方法中直接從Provider字段中g(shù)et相應(yīng)的對象就行。就相當(dāng)于我們的水車已經(jīng)順利的水源取水了腻窒。

3.總結(jié)
總而言之,Dagger根據(jù)@Provider直接生成相應(yīng)的工廠類和DaggerApplicationComponent 類磅崭,DaggerApplicationComponent 類持有Module和相應(yīng)的工廠類字段儿子,實(shí)現(xiàn)了從水源取水這一過程。
第二篇比較枯燥砸喻,全是代碼的解讀和分析柔逼。下一篇我們將關(guān)注@Inject是怎樣實(shí)現(xiàn)注入的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末割岛,一起剝皮案震驚了整個(gè)濱河市愉适,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌癣漆,老刑警劉巖维咸,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異惠爽,居然都是意外死亡癌蓖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進(jìn)店門婚肆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來租副,“玉大人,你說我怎么就攤上這事较性∮蒙” “怎么了?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵赞咙,是天一觀的道長责循。 經(jīng)常有香客問我,道長人弓,這世上最難降的妖魔是什么沼死? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮崔赌,結(jié)果婚禮上意蛀,老公的妹妹穿的比我還像新娘耸别。我一直安慰自己,他們只是感情好县钥,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布秀姐。 她就那樣靜靜地躺著,像睡著了一般若贮。 火紅的嫁衣襯著肌膚如雪省有。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天谴麦,我揣著相機(jī)與錄音蠢沿,去河邊找鬼。 笑死匾效,一個(gè)胖子當(dāng)著我的面吹牛舷蟀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播面哼,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼野宜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了魔策?” 一聲冷哼從身側(cè)響起匈子,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎闯袒,沒想到半個(gè)月后虎敦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搁吓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年桑阶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了身冀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,912評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖霜医,靈堂內(nèi)的尸體忽然破棺而出睹簇,到底是詐尸還是另有隱情大脉,我是刑警寧澤焊夸,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站恼五,受9級(jí)特大地震影響昌罩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜灾馒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一茎用、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦轨功、人聲如沸旭斥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垂券。三九已至,卻和暖如春羡滑,著一層夾襖步出監(jiān)牢的瞬間菇爪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工柒昏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凳宙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓昙楚,卻偏偏與公主長得像近速,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子堪旧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)奖亚,斷路器淳梦,智...
    卡卡羅2017閱讀 134,716評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,332評論 25 707
  • 你走在深夜里, 在昏黃的路燈下昔字, 遙遠(yuǎn)的星和月在污濁的天空里爆袍, 更加遙遠(yuǎn)。 偶爾吹起的晚風(fēng)作郭, 讓不安分的浮塵在燈光...
    簡客子閱讀 202評論 0 0
  • 上海的今天是風(fēng)雨交加的陨囊,再不寫點(diǎn)東西我覺得自己已經(jīng)綜述能力越來略差了 好想記錄下生活的點(diǎn)點(diǎn)滴滴,好想記錄下自己那一...
    向往溫暖閱讀 418評論 1 2
  • 今天看了喜歡的電影《Begin Again》夹攒,中途竟然兩次哽咽~ 當(dāng)?shù)谝粋€(gè)鏡頭里蜘醋,凱拉.奈特莉憂郁的眼神出現(xiàn)時(shí),我...
    這天氣很晴朗閱讀 224評論 0 1