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)方法:

 package com.example.android.architecture.blueprints.todoapp.tasks;

 import com.example.android.architecture.blueprints.todoapp.ToDoApplication;
import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepositoryComponent;
import com.example.android.architecture.blueprints.todoapp.util.FragmentScoped; import dagger.Component; /**
* This is a Dagger component. Refer to {@link ToDoApplication} for the list of Dagger components
* used in this application.
* <P>
* Because this component depends on the {@link TasksRepositoryComponent}, which is a singleton, a
* scope must be specified. All fragment components use a custom scope for this purpose.
*/
@FragmentScoped
@Component(dependencies = TasksRepositoryComponent.class, modules = TasksPresenterModule.class)
public interface TasksComponent { void inject(TasksActivity activity); }

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

 package com.example.android.architecture.blueprints.todoapp.tasks;

 import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepository;
import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepositoryComponent; import javax.annotation.Generated;
import javax.inject.Provider; import dagger.MembersInjector;
import dagger.internal.Factory;
import dagger.internal.Preconditions; @Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class DaggerTasksComponent implements TasksComponent {
private MembersInjector<TasksPresenter> tasksPresenterMembersInjector; private Provider<TasksRepository> getTasksRepositoryProvider; private Provider<TasksContract.View> provideTasksContractViewProvider; private Provider<TasksPresenter> tasksPresenterProvider; private MembersInjector<TasksActivity> tasksActivityMembersInjector; private DaggerTasksComponent(Builder builder) {
assert builder != null;
initialize(builder);
} public static Builder builder() {
return new Builder();
} @SuppressWarnings("unchecked")
private void initialize(final Builder builder) { this.tasksPresenterMembersInjector = TasksPresenter_MembersInjector.create(); this.getTasksRepositoryProvider =
new Factory<TasksRepository>() {
private final TasksRepositoryComponent tasksRepositoryComponent =
builder.tasksRepositoryComponent; @Override
public TasksRepository get() {
return Preconditions.checkNotNull(
tasksRepositoryComponent.getTasksRepository(),
"Cannot return null from a non-@Nullable component method");
}
}; this.provideTasksContractViewProvider =
TasksPresenterModule_ProvideTasksContractViewFactory.create(builder.tasksPresenterModule); this.tasksPresenterProvider =
TasksPresenter_Factory.create(
tasksPresenterMembersInjector,
getTasksRepositoryProvider,
provideTasksContractViewProvider); this.tasksActivityMembersInjector =
TasksActivity_MembersInjector.create(tasksPresenterProvider);
} @Override
public void inject(TasksActivity activity) {
tasksActivityMembersInjector.injectMembers(activity);
} public static final class Builder {
private TasksPresenterModule tasksPresenterModule; private TasksRepositoryComponent tasksRepositoryComponent; private Builder() {
} public TasksComponent build() {
if (tasksPresenterModule == null) {
throw new IllegalStateException(
TasksPresenterModule.class.getCanonicalName() + " must be set");
}
if (tasksRepositoryComponent == null) {
throw new IllegalStateException(
TasksRepositoryComponent.class.getCanonicalName() + " must be set");
}
return new DaggerTasksComponent(this);
} public Builder tasksPresenterModule(TasksPresenterModule tasksPresenterModule) {
this.tasksPresenterModule = Preconditions.checkNotNull(tasksPresenterModule);
return this;
} public Builder tasksRepositoryComponent(TasksRepositoryComponent tasksRepositoryComponent) {
this.tasksRepositoryComponent = Preconditions.checkNotNull(tasksRepositoryComponent);
return this;
}
}
}

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

 tasksActivityMembersInjector.injectMembers(activity);

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

 package dagger;

 /**
* Injects dependencies into the fields and methods on instances of type {@code T}. Ignores the
* presence or absence of an injectable constructor.
*
* @param <T> type to inject members of
*
* @author Bob Lee
* @author Jesse Wilson
* @since 2.0 (since 1.0 without the provision that {@link #injectMembers} cannot accept
* {@code null})
*/
public interface MembersInjector<T> { /**
* Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or
* absence of an injectable constructor.
*
* <p>Whenever the object graph creates an instance, it performs this injection automatically
* (after first performing constructor injection), so if you're able to let the object graph
* create all your objects for you, you'll never need to use this method.
*
* @param instance into which members are to be injected
* @throws NullPointerException if {@code instance} is {@code null}
*/
void injectMembers(T instance);
}

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

 this.tasksActivityMembersInjector = TasksActivity_MembersInjector.create(tasksPresenterProvider);
  TasksActivity_MembersInjector的create()方法创建了tasksActivityMembersInjector。于是,我们再来看TasksActivity_MembersInjector这个类,TasksActivity_MembersInjector代码如下:
 package com.example.android.architecture.blueprints.todoapp.tasks;

 import javax.annotation.Generated;
import javax.inject.Provider; import dagger.MembersInjector; @Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class TasksActivity_MembersInjector implements MembersInjector<TasksActivity> {
private final Provider<TasksPresenter> mTasksPresenterProvider; public TasksActivity_MembersInjector(Provider<TasksPresenter> mTasksPresenterProvider) {
assert mTasksPresenterProvider != null;
this.mTasksPresenterProvider = mTasksPresenterProvider;
} public static MembersInjector<TasksActivity> create(
Provider<TasksPresenter> mTasksPresenterProvider) {
return new TasksActivity_MembersInjector(mTasksPresenterProvider);
} @Override
public void injectMembers(TasksActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mTasksPresenter = mTasksPresenterProvider.get();
} public static void injectMTasksPresenter(
TasksActivity instance, Provider<TasksPresenter> mTasksPresenterProvider) {
instance.mTasksPresenter = mTasksPresenterProvider.get();
}
}
  TasksActivity_MembersInjector正是刚刚我们所看的MembersInjector<T>的一个实现类,TasksActivity_MembersInjector实现了injectMembers(),在injectMembers()的实现中干了这么一件事情:
 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的代码:

 package com.example.android.architecture.blueprints.todoapp.tasks;

 import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepository;

 import javax.annotation.Generated;
import javax.inject.Provider; import dagger.MembersInjector;
import dagger.internal.Factory;
import dagger.internal.MembersInjectors; @Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class TasksPresenter_Factory implements Factory<TasksPresenter> {
private final MembersInjector<TasksPresenter> tasksPresenterMembersInjector; private final Provider<TasksRepository> tasksRepositoryProvider; private final Provider<TasksContract.View> tasksViewProvider; public TasksPresenter_Factory(
MembersInjector<TasksPresenter> tasksPresenterMembersInjector,
Provider<TasksRepository> tasksRepositoryProvider,
Provider<TasksContract.View> tasksViewProvider) {
assert tasksPresenterMembersInjector != null;
this.tasksPresenterMembersInjector = tasksPresenterMembersInjector;
assert tasksRepositoryProvider != null;
this.tasksRepositoryProvider = tasksRepositoryProvider;
assert tasksViewProvider != null;
this.tasksViewProvider = tasksViewProvider;
} @Override
public TasksPresenter get() {
return MembersInjectors.injectMembers(
tasksPresenterMembersInjector,
new TasksPresenter(tasksRepositoryProvider.get(), tasksViewProvider.get()));
} public static Factory<TasksPresenter> create(
MembersInjector<TasksPresenter> tasksPresenterMembersInjector,
Provider<TasksRepository> tasksRepositoryProvider,
Provider<TasksContract.View> tasksViewProvider) {
return new TasksPresenter_Factory(
tasksPresenterMembersInjector, tasksRepositoryProvider, tasksViewProvider);
}
}

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

浅析Dagger2依赖注入实现过程的更多相关文章

  1. Android——初探Dagger2依赖注入

    1,在做项目时,经常需要在一个对象里去创建另一个对象的示例,这种行为是产生耦合的常见形式,对于一个大型项目来说,过多的相互依赖会导致代码难以维护,很容易就会碰到修改一个小需求需要大面积的修改各种代码, ...

  2. 浅析“依赖注入(DI)/控制反转(IOC)”的实现思路

    开始学习Spring的时候,对依赖注入(DI)——也叫控制反转(IOC)—— 的理解不是很深刻.随着学习的深入,也逐渐有了自己的认识,在此记录,也希望能帮助其他入门同学更深入地理解Spring.本文不 ...

  3. 框架源码系列九:依赖注入DI、三种Bean配置方式的注册和实例化过程

    一.依赖注入DI 学习目标1)搞清楚构造参数依赖注入的过程及类2)搞清楚注解方式的属性依赖注入在哪里完成的.学习思路1)思考我们手写时是如何做的2)读 spring 源码对比看它的实现3)Spring ...

  4. 用Dagger2在Android中实现依赖注入

    依赖注入这个模式(模式已经用烂了,这里再烂一次)是用来给应用的各部分解耦的.使应用开发更加可扩展,更容易维护.通过本文你会学到如何使用Dagger2来处理依赖. 简介 如果以对象需要另外的一个对象才能 ...

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

    ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...

  6. 轻松了解Spring中的控制反转和依赖注入(一)

    我们回顾一下计算机的发展史,从最初第一台计算机的占地面积达170平方米,重达30吨,到现如今的个人笔记本,事物更加轻量功能却更加丰富,这是事物发展过程中的一个趋势,在技术领域中同样也是如此,企业级Ja ...

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

    前言 最近在学习Spring框架,它的核心就是IoC容器.要掌握Spring框架,就必须要理解控制反转的思想以及依赖注入的实现方式.下面,我们将围绕下面几个问题来探讨控制反转与依赖注入的关系以及在Sp ...

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

    1 IoC理论的背景    我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑.  图1:软件系统中耦合的对象 如果我们 ...

  9. 控制反转IOC与依赖注入DI【转】

    转自:http://my.oschina.net/1pei/blog/492601 一直对控制反转.依赖注入不太明白,看到这篇文章感觉有点懂了,介绍的很详细. 1. IoC理论的背景我们都知道,在采用 ...

随机推荐

  1. .Net Core 扩展使用Refit

    .Net Core 扩展使用Refit 标签(空格分隔): 未分类 在.net core 2.1当中,目前可以是用HttpClientFactory进行Http的调用,它的使用方法我不再多说,具体参见 ...

  2. Exception异常处理

    1.java异常类: 都是Throwable的子类: 1.Exception(异常) :是程序本身可以处理的异常. 2.Error(错误): 是程序无法处理的错误.这些错误表示故障发生于虚拟机自身.或 ...

  3. [Xcode 实际操作]三、视图控制器-(9)在Storyboard中使用标签和按钮控件

    目录:[Swift]Xcode实际操作 本文将演示标签和按钮在故事板中的应用. 在欢迎串口中,点击创建一个新的项目[Create a new Xcode project] [Single View A ...

  4. [Xcode 实际操作]四、常用控件-(10)动作表样式警告窗口的使用

    目录:[Swift]Xcode实际操作 本文将演示动作表单窗口的使用. 动作表单可以给用户展现一系列的选项, 和警告窗口不同的是,动作表单的展示形式和设备的尺寸有关. 在项目导航区,打开视图控制器的代 ...

  5. 前端页面使用ace插件优化脚本

    html页面:<pre id="editor" style="width: 100%;height: 800px;"></pre>(注: ...

  6. 历年NOIP真题总结

    前言:最近把历年的NOIP真题肝了一遍(还有3个紫题先咕掉了),主要是到1998年的提高组的题.把题目的做题简要思路搁在这儿,一个是为了考前翻一翻,想想自己的哪些思路要梳理的什么什么的,反正怎么说呢, ...

  7. [AHOI2009]飞行棋 BZOJ1800

    题目描述 给出圆周上的若干个点,已知点与点之间的弧长,其值均为正整数,并依圆周顺序排列. 请找出这些点中有没有可以围成矩形的,并希望在最短时间内找出所有不重复矩形. 输入输出格式 输入格式: 第一行为 ...

  8. Java中的生产者和消费者实例(多线程 等待唤醒机制)

    1.什么是等待唤醒 我们实现的效果 创建生产者和消费者  对服装进行生产  和售卖 实现生产一个就消费一个 来观察线程的各种状态 下面是用到的方法: wait()方法:让一个线程进行等待 另外一个线程 ...

  9. mycat学习日记:关于联表查询

    https://www.cnblogs.com/toulon/p/4832895.html 在使用数据库中间件之前,我就想到分库分表的操作对于联表操作可能会显得非常复杂.因为如果数据是分片存储的,如果 ...

  10. 【ACM】一种排序

    一种排序 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复:还知道这个长方形的宽和长,编号.长.宽都是整数 ...