浅析Dragger2依赖注入实现过程

  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 [email protected] 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中的依赖注入实现,待领悟再深入一个层次之后再发一篇总结性文章。

时间: 2024-10-24 00:02:46

浅析Dragger2依赖注入实现过程的相关文章

ABP源码分析六:依赖注入的实现

ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的类定义Register 规则,然后通过IocManager来读取这个规则完成依赖注入.3另一种实现途径是直接IocManager的Register方法完成注入. 第一种途径: 下面具体分析:代码在Abp项目文件的Dependency文件夹下. 先出一张相关接口和类的关系图,然后逐个解释. IDictionary

控制反转(IoC)与依赖注入(DI)

前言 最近在学习Spring框架,它的核心就是IoC容器.要掌握Spring框架,就必须要理解控制反转的思想以及依赖注入的实现方式.下面,我们将围绕下面几个问题来探讨控制反转与依赖注入的关系以及在Spring中如何应用. 什么是控制反转? 什么是依赖注入? 它们之间有什么关系? 如何在Spring框架中应用依赖注入? 什么是控制反转 在讨论控制反转之前,我们先来看看软件系统中耦合的对象.图1:软件系统中耦合的对象从图中可以看到,软件中的对象就像齿轮一样,协同工作,但是互相耦合,一个零件不能正常工

依赖注入与控制反转

抄自:http://blog.xiaohansong.com/2015/10/21/IoC-and-DI/ 找不到比这更清楚明白的了 场景:对象A依赖于对象B 控制反转: 控制反转前:由在类A中初始化B,对象A控制着对象B的初始化和使用, 控制反转后:对象B的初始化在对象A需要时由容器初始化并注入到对象A中,控制权在容器手上. 对象A对对象B的依赖,由主动变成了被动,控制权颠倒过来了,对象A与B解耦 依赖注入:就是将实例变量传入到一个对象中去.非自己主动初始化依赖,而通过外部来传入依赖的方式 前

spring源码——资源的注册及依赖注入

一 注册 注册过程并不复杂,就是把解析得到的beandefinition设置到hashmap中去.需要注意的是,如果遇到同名的beandefinition,需要去判断allowbeandefinitionoverriding属性,如果不允许会抛出异常.把bean的名字存入beandefinitionnames,且beanname会作为map的key ,beandefinition作为value. 这里的map名字是beandefinitionmap,,它被ioc容器持有. 至此,ioc的初始化就

控制反转IOC与依赖注入DI

1. IoC理论的背景我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图1:软件系统中耦合的对象 如果我们打开机械式手表的后盖,就会看到与上面类似的情形,各个齿轮分别带动时针.分针和秒针顺时针旋转,从而在表盘上产生正确的时间.图1中描述的就是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一起,协同工作,共同完成某项任务.我们可以看到,在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到整个齿轮组

【架构师之路】依赖注入原理---IoC框架

1 IoC理论的背景    我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑.  图1:软件系统中耦合的对象 如果我们打开机械式手表的后盖,就会看到与上面类似的情形,各个齿轮分别带动时针.分针和秒针顺时针旋转,从而在表盘上产生正确的时间.图1中描述的就是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一起,协同工作,共同完成某项任务.我们可以看到,在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到整

Spring学习笔记——Spring依赖注入原理分析

我们知道Spring的依赖注入有四种方式,分别是get/set方法注入.构造器注入.静态工厂方法注入.实例工厂方法注入 下面我们先分析下这几种注入方式 1.get/set方法注入 public class SpringAction { //注入对象springDao private SpringDao springDao; //一定要写被注入对象的set方法 public void setSpringDao(SpringDao springDao) { this.springDao = spri

Dagger——Android上的依赖注入框架

* 你也可以去Github查看这片文章 简介 在开发程序的时候,会用到各种对象,很多对象在使用之前都需要进行初始化.例如你要操作一个SharedPreference,你需要调用getSharedPreferences(String name,int mode)来获取一个对象,然后才能使用它.而如果这个对象会在多个Activity中被使用,你就需要在每个使用的场景中都写下同样的代码.这不仅麻烦,而且增加了出错的可能.dagger的用途就是:让你不需要初始化对象.换句话说,任何对象声明完了就能直接用

轻松了解Spring中的控制反转和依赖注入

我们回顾一下计算机的发展史,从最初第一台计算机的占地面积达170平方米,重达30吨,到现如今的个人笔记本,事物更加轻量功能却更加丰富,这是事物发展过程中的一个趋势,在技术领域中同样也是如此,企业级JavaBean(Enterprise JavaBean ,EJB)在创建之初是非常成功,但是时间一久人们便开始追逐更加方便更加简易和轻量级的技术框架实现,于是Spring就应运而生,并且Sring一直开始不断地涉及到其他领域(这里就不再多详谈了),而Spring的精髓当中就包括控制反转和依赖注入. 浅