zoukankan      html  css  js  c++  java
  • 浅析Dagger2依赖注入实现过程

      Dragger2是Android应用开发中一个非常优秀的依赖注入框架。本文主要通过结合Google给出的MVP开发案例todo-mvp-dagger(GitHub连接地址:https://github.com/googlesamples/android-architecture/tree/todo-mvp-dagger/),简要分析一下Dragger2的依赖注入实现过程。

      如果是刚入手学习Dragger2,这里推荐三篇非常不错的连载文章:http://www.jianshu.com/p/cd2c1c9f68d4,这三篇文章写得非常用心,而且思路清晰,生动有趣,容易理解。

      todo-mvp-dagger在功能上划分为addedittask,statistics,taskdetail,tasks四个模块,由于每个模块除了功能逻辑不同之外,实现方式相差不大,所以我就只分析其中的tasks模块,其它模块可参照此模块的分析流程来分析。

      Dragger2的依赖注入是通过Java注解的方式来实现的。Dragger2中提供了@Inject,@Component,@Module,@Provides等一系列注解,通过注解,Dragger2能够在程序编译阶段利用程序员创建的Java文件,按照编译模板自动生成对应的.class辅助文件,在这些.class辅助文件中会有相应代码来自动完成依赖对象的创建。Dragger2正是以此种看似自动化的技术手段来代替手动new对象的过程。如下图,红色框中的.class文件就是Tasks模块在编译过后自动生成的.class辅助文件。

      其实,现在有很多框架都利用了注解的方式,通过在编译阶段生成相应的.class文件来完成依赖注入或者其它某些操作,如阿里已经开源的路由框架ARouter。

      那Dragger2的依赖注入究竟是怎样的一个过程呢?我们先来看TasksActivity。下面是TasksActivity的部分代码。

      TasksActivity中依赖了一个对象:mTasksPresenter。mTasksPresenter用@Inject标注,表示在TasksActivity实例化时,mTasksPresenter需要被自动创建,然后注入到TasksActivity实例当中去。此时,我们可能会想,是不是用@Inject标注一下就实现依赖注入了?其实不然。我们看到上图下方的红色框中有一段代码,这段代码很长,因为DaggerTasksComponent这个类中使用了Builder模式,只要稍微拆分一下明白了,其实这段代码就做了一件事情,就是调用了TasksComponent的inject()方法,而这里才是mTasksPresenter真正被实例化的地方。

      我们再来看TasksComponent,这是一个很简单的接口,里面声明了一个inject(TasksActivity activity)方法:

     1 package com.example.android.architecture.blueprints.todoapp.tasks;
     2 
     3 import com.example.android.architecture.blueprints.todoapp.ToDoApplication;
     4 import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepositoryComponent;
     5 import com.example.android.architecture.blueprints.todoapp.util.FragmentScoped;
     6 
     7 import dagger.Component;
     8 
     9 /**
    10  * This is a Dagger component. Refer to {@link ToDoApplication} for the list of Dagger components
    11  * used in this application.
    12  * <P>
    13  * Because this component depends on the {@link TasksRepositoryComponent}, which is a singleton, a
    14  * scope must be specified. All fragment components use a custom scope for this purpose.
    15  */
    16 @FragmentScoped
    17 @Component(dependencies = TasksRepositoryComponent.class, modules = TasksPresenterModule.class)
    18 public interface TasksComponent {
    19     
    20     void inject(TasksActivity activity);
    21 
    22 }

      有接口,对应的一般就有实现类,TasksComponent的实现类在哪里呢?我们注意到TasksComponent 被@Component标注,@Component是干什么的?@Component是用来标识接口或者抽象类,被@Componen标注的接口或者抽象类,在程序编译阶段会自动生成带Dragger前缀的.class文件,例如TasksComponent 被@Component标注,就会生成DraggerTasksComponent.class文件。生成的.class文件便是被@Component标注的接口或者抽象类的实现。我们点开DraggerTasksComponent.class,其中的代码是这样子的:

      1 package com.example.android.architecture.blueprints.todoapp.tasks;
      2 
      3 import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepository;
      4 import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepositoryComponent;
      5 
      6 import javax.annotation.Generated;
      7 import javax.inject.Provider;
      8 
      9 import dagger.MembersInjector;
     10 import dagger.internal.Factory;
     11 import dagger.internal.Preconditions;
     12 
     13 @Generated(
     14         value = "dagger.internal.codegen.ComponentProcessor",
     15         comments = "https://google.github.io/dagger"
     16 )
     17 public final class DaggerTasksComponent implements TasksComponent {
     18     private MembersInjector<TasksPresenter> tasksPresenterMembersInjector;
     19 
     20     private Provider<TasksRepository> getTasksRepositoryProvider;
     21 
     22     private Provider<TasksContract.View> provideTasksContractViewProvider;
     23 
     24     private Provider<TasksPresenter> tasksPresenterProvider;
     25 
     26     private MembersInjector<TasksActivity> tasksActivityMembersInjector;
     27 
     28     private DaggerTasksComponent(Builder builder) {
     29         assert builder != null;
     30         initialize(builder);
     31     }
     32 
     33     public static Builder builder() {
     34         return new Builder();
     35     }
     36 
     37     @SuppressWarnings("unchecked")
     38     private void initialize(final Builder builder) {
     39 
     40         this.tasksPresenterMembersInjector = TasksPresenter_MembersInjector.create();
     41 
     42         this.getTasksRepositoryProvider =
     43                 new Factory<TasksRepository>() {
     44                     private final TasksRepositoryComponent tasksRepositoryComponent =
     45                             builder.tasksRepositoryComponent;
     46 
     47                     @Override
     48                     public TasksRepository get() {
     49                         return Preconditions.checkNotNull(
     50                                 tasksRepositoryComponent.getTasksRepository(),
     51                                 "Cannot return null from a non-@Nullable component method");
     52                     }
     53                 };
     54 
     55         this.provideTasksContractViewProvider =
     56                 TasksPresenterModule_ProvideTasksContractViewFactory.create(builder.tasksPresenterModule);
     57 
     58         this.tasksPresenterProvider =
     59                 TasksPresenter_Factory.create(
     60                         tasksPresenterMembersInjector,
     61                         getTasksRepositoryProvider,
     62                         provideTasksContractViewProvider);
     63 
     64         this.tasksActivityMembersInjector =
     65                 TasksActivity_MembersInjector.create(tasksPresenterProvider);
     66     }
     67 
     68     @Override
     69     public void inject(TasksActivity activity) {
     70         tasksActivityMembersInjector.injectMembers(activity);
     71     }
     72 
     73     public static final class Builder {
     74         private TasksPresenterModule tasksPresenterModule;
     75 
     76         private TasksRepositoryComponent tasksRepositoryComponent;
     77 
     78         private Builder() {
     79         }
     80 
     81         public TasksComponent build() {
     82             if (tasksPresenterModule == null) {
     83                 throw new IllegalStateException(
     84                         TasksPresenterModule.class.getCanonicalName() + " must be set");
     85             }
     86             if (tasksRepositoryComponent == null) {
     87                 throw new IllegalStateException(
     88                         TasksRepositoryComponent.class.getCanonicalName() + " must be set");
     89             }
     90             return new DaggerTasksComponent(this);
     91         }
     92 
     93         public Builder tasksPresenterModule(TasksPresenterModule tasksPresenterModule) {
     94             this.tasksPresenterModule = Preconditions.checkNotNull(tasksPresenterModule);
     95             return this;
     96         }
     97 
     98         public Builder tasksRepositoryComponent(TasksRepositoryComponent tasksRepositoryComponent) {
     99             this.tasksRepositoryComponent = Preconditions.checkNotNull(tasksRepositoryComponent);
    100             return this;
    101         }
    102     }
    103 }

      DaggerTasksComponent采用了Builder模式进行设计,实现了inject(TasksActivity activity)方法。DaggerTasksComponent中的代码有一点点多,而且成员变量都是泛型类对象,看似稍微有点复杂,我们可以整体大概看一下,然后还是从inject(TasksActivity activity)方法的实现入手。inject(TasksActivity activity)的实现很简单,就一行代码:

    1 tasksActivityMembersInjector.injectMembers(activity);

      这一行代码调用了接口MembersInjector<T>的void injectMembers(T instance)方法,好,接下来我们看看MembersInjector<T>以及其中的void injectMembers(T instance)方法是用来做什么的。MembersInjector<T>的代码如下:

     1 package dagger;
     2 
     3 /**
     4  * Injects dependencies into the fields and methods on instances of type {@code T}. Ignores the
     5  * presence or absence of an injectable constructor.
     6  *
     7  * @param <T> type to inject members of
     8  *
     9  * @author Bob Lee
    10  * @author Jesse Wilson
    11  * @since 2.0 (since 1.0 without the provision that {@link #injectMembers} cannot accept
    12  *      {@code null})
    13  */
    14 public interface MembersInjector<T> {
    15 
    16   /**
    17    * Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or
    18    * absence of an injectable constructor.
    19    *
    20    * <p>Whenever the object graph creates an instance, it performs this injection automatically
    21    * (after first performing constructor injection), so if you're able to let the object graph
    22    * create all your objects for you, you'll never need to use this method.
    23    *
    24    * @param instance into which members are to be injected
    25    * @throws NullPointerException if {@code instance} is {@code null}
    26    */
    27   void injectMembers(T instance);
    28 }

      看过注释,我们知道了,原来这个接口就是用来将依赖注入到目标实体(即依赖对象所依附的实体,显然,这里就是指TasksActivity)当中去。到这里,我们好像有点眉目了。不着急,我们继续看MembersInjector<T>的实现。刚刚我们看了DaggerTasksComponent中inject(TasksActivity activity)方法的实现,里面的tasksActivityMembersInjector对象调用了injectMembers()方法,因此可断定tasksActivityMembersInjector就是MembersInjector<T>的实现类对象,那么,tasksActivityMembersInjector是怎么得来的呢?继续看DaggerTasksComponent的代码,发现tasksActivityMembersInjector是这样被创建的:

    1 this.tasksActivityMembersInjector = TasksActivity_MembersInjector.create(tasksPresenterProvider);
      TasksActivity_MembersInjector的create()方法创建了tasksActivityMembersInjector。于是,我们再来看TasksActivity_MembersInjector这个类,TasksActivity_MembersInjector代码如下:
     1 package com.example.android.architecture.blueprints.todoapp.tasks;
     2 
     3 import javax.annotation.Generated;
     4 import javax.inject.Provider;
     5 
     6 import dagger.MembersInjector;
     7 
     8 @Generated(
     9         value = "dagger.internal.codegen.ComponentProcessor",
    10         comments = "https://google.github.io/dagger"
    11 )
    12 public final class TasksActivity_MembersInjector implements MembersInjector<TasksActivity> {
    13     private final Provider<TasksPresenter> mTasksPresenterProvider;
    14 
    15     public TasksActivity_MembersInjector(Provider<TasksPresenter> mTasksPresenterProvider) {
    16         assert mTasksPresenterProvider != null;
    17         this.mTasksPresenterProvider = mTasksPresenterProvider;
    18     }
    19 
    20     public static MembersInjector<TasksActivity> create(
    21             Provider<TasksPresenter> mTasksPresenterProvider) {
    22         return new TasksActivity_MembersInjector(mTasksPresenterProvider);
    23     }
    24 
    25     @Override
    26     public void injectMembers(TasksActivity instance) {
    27         if (instance == null) {
    28             throw new NullPointerException("Cannot inject members into a null reference");
    29         }
    30         instance.mTasksPresenter = mTasksPresenterProvider.get();
    31     }
    32 
    33     public static void injectMTasksPresenter(
    34             TasksActivity instance, Provider<TasksPresenter> mTasksPresenterProvider) {
    35         instance.mTasksPresenter = mTasksPresenterProvider.get();
    36     }
    37 }
      TasksActivity_MembersInjector正是刚刚我们所看的MembersInjector<T>的一个实现类,TasksActivity_MembersInjector实现了injectMembers(),在injectMembers()的实现中干了这么一件事情:
    1 instance.mTasksPresenter = mTasksPresenterProvider.get();

      哦!原来TasksActivity中的mTasksPresenter是通过mTasksPresenterProvider.get()得来的!此时,迷雾变得逐渐清晰了!接下来再看mTasksPresenterProvider是如何来的。

      mTasksPresenterProvider在TasksActivity_MembersInjector的构造方法中被赋值,而TasksActivity_MembersInjector的构造方法是在create()方法中被调用的,于是,我们回到DaggerTasksComponent中调用TasksActivity_MembersInjector的create()方法的地方。找到传入create()方法的参数tasksPresenterProvider,发现tasksPresenterProvider又是由TasksPresenter_Factory的create()方法创建的。接下来,我们进一步看TasksPresenter_Factory的代码:

     1 package com.example.android.architecture.blueprints.todoapp.tasks;
     2 
     3 import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepository;
     4 
     5 import javax.annotation.Generated;
     6 import javax.inject.Provider;
     7 
     8 import dagger.MembersInjector;
     9 import dagger.internal.Factory;
    10 import dagger.internal.MembersInjectors;
    11 
    12 @Generated(
    13         value = "dagger.internal.codegen.ComponentProcessor",
    14         comments = "https://google.github.io/dagger"
    15 )
    16 public final class TasksPresenter_Factory implements Factory<TasksPresenter> {
    17     private final MembersInjector<TasksPresenter> tasksPresenterMembersInjector;
    18 
    19     private final Provider<TasksRepository> tasksRepositoryProvider;
    20 
    21     private final Provider<TasksContract.View> tasksViewProvider;
    22 
    23     public TasksPresenter_Factory(
    24             MembersInjector<TasksPresenter> tasksPresenterMembersInjector,
    25             Provider<TasksRepository> tasksRepositoryProvider,
    26             Provider<TasksContract.View> tasksViewProvider) {
    27         assert tasksPresenterMembersInjector != null;
    28         this.tasksPresenterMembersInjector = tasksPresenterMembersInjector;
    29         assert tasksRepositoryProvider != null;
    30         this.tasksRepositoryProvider = tasksRepositoryProvider;
    31         assert tasksViewProvider != null;
    32         this.tasksViewProvider = tasksViewProvider;
    33     }
    34 
    35     @Override
    36     public TasksPresenter get() {
    37         return MembersInjectors.injectMembers(
    38                 tasksPresenterMembersInjector,
    39                 new TasksPresenter(tasksRepositoryProvider.get(), tasksViewProvider.get()));
    40     }
    41 
    42     public static Factory<TasksPresenter> create(
    43             MembersInjector<TasksPresenter> tasksPresenterMembersInjector,
    44             Provider<TasksRepository> tasksRepositoryProvider,
    45             Provider<TasksContract.View> tasksViewProvider) {
    46         return new TasksPresenter_Factory(
    47                 tasksPresenterMembersInjector, tasksRepositoryProvider, tasksViewProvider);
    48     }
    49 }

      我们发现,在TasksPresenter_Factory实现的get()方法中,一个匿名TasksPresenter对象被创建,这个匿名对象正是被注入到TasksActivity的依赖对象!

      我们再回过头来看,因为这里的get()方法其实就是Provider<TasksPresenter>的具体实现,在TasksActivity_MembersInjector中的injectMembers(TasksActivity instance)方法中被TasksActivity_MembersInjector的成员变量mTasksPresenterProvider调用,mTasksPresenterProvider调用get()方法后返回的结果被赋值给TasksActivity实例中的依赖对象mTasksPresenter。

      至此,Dragger2中一个完整的依赖注入过程分析就此结束。诚然,本文只是简单梳理了一下依赖注入的整个流程,对于更深层次的问题,如:Dragger是如何设计.class文件自动生成模板的,自动生成.class文件的具体过程是什么样的等等,本文暂时没有说明,这也是我接下来要做的事情,刚好这几天也在看ARouter的源码,发现其中的依赖注入实现和Dragger2差不多,所以,我打算从多个源码框架中来对比分析和总结Android中的依赖注入实现,待领悟再深入一个层次之后再发一篇总结性文章。

  • 相关阅读:
    IDEA下同时使用Git和svn
    IDEA进行activiti-archetype-unittest脚手架的安装
    正则表达式
    关于JS堆栈与拷贝
    按值传递--
    JS---变量、作用域和内存问题
    laod
    待解决
    闭包2
    闭包1
  • 原文地址:https://www.cnblogs.com/1992monkey/p/7062630.html
Copyright © 2011-2022 走看看