依赖注入及Dagger2框架简介

依赖注入简介

在介绍Dagger框架之前我们先来看看依赖注入(Dependence Injection),依赖注入还有另一个名字叫控制反转(Inversion of Control,英文缩写为IoC),当你看到这两个名词时他们大多指的都是同一个概念(实际上依赖注入是控制反转的一部分,其另一部分称为依赖查找(Dependenc Lookup)使用相对较少且不在本文涉及范畴),那什么是依赖注入呢?依赖了什么?又注入了什么?

不懂的东西我们自然要去问谷哥和度娘了,我搜到了一篇文章讲的还满详细的,大家可以去学习一下:依赖注入那些事儿,这篇文章虽然是基于c#语言写的但是用在JAVA上也是丝毫没有问题的。

在默认大家已经读了上面那个链接里的文章N遍以后,我来用简单的语言总结一下通常的代码结构中,调用者会直接决定实现的方式,比如调用者需要一本书的实例,在初始化的时候就会决定这本书是语文书还是数学书。而在依赖注入的世界里调用者只会声明我需要一本书,而在执行的时候才会根据外部条件决定给调用者语文书还是数学书。

无论你是否理解了依赖注入,我们先来看下依赖注入的优缺点(这些点可能部分和Dagger框架会不一致,仅供增进大家对依赖注入的理解):

优点:

  • 代码分层:把逻辑分层后每层可以独立的编写和进行单元测试,而不用担心影响到其他层的功能(只要不改变接口的实现)
  • 动态配置:通过XML等方式以及反射机制可以在运行时改变程序的行为而不必重新编译代码
  • 让框架看起来更高端(这个是随便BB的啦)

不足:

  • 生成一个对象的步骤变复杂了(事实上操作上还是挺简单的),对于不习惯这种方式的人,会觉得有些别扭和不直观。
  • 对象生成因为是使用反射编程,在效率上有些损耗。但相对于IoC提高的维护性和灵活性来说,这点损耗是微不足道的,除非某对象的生成对效率要求特别高。
  • 缺少IDE重构操作的支持,如果在Eclipse要对类改名,那么你还需要去XML文件里手工去改了,这似乎是所有XML方式的缺憾所在。

Dagger2框架简介及实用

以下部分内容引用自详解Dagger2

Dagger1简介

有Dagger2自然就有Dagger1,先简单说下Dagger1。Dagger1框架是由Square公司受到Guice启发创建的,也是Android上最常用的依赖注入框架

Dagger1基本特点:

  • 多个注入点:依赖,通过injected
  • 多种绑定方法:依赖,通过provided
  • 多个modules:实现某种功能的绑定集合
  • 多个对象图: 实现一个范围的modules集合

Dagger1是在编译的时候实行绑定,不过也用到了反射机制。但这个反射不是用来实例化对象的,而是用于图的构成。Dagger会在运行的时候去检测是否一切都正常工作,所以使用的时候会付出一些代价:偶尔会无效和调试困难。

详细的细节我们就不多说了,这不是我们关注的重点。

Dagger2简介

Dagger2是Dagger1的分支,由谷歌公司接手开发,目前的版本是2.0。Dagger2是受到AutoValue项目的启发。 刚开始,Dagger2解决问题的基本思想是:利用生成和写的代码混合达到看似所有的产生和提供依赖的代码都是手写的样子。

如果我们将Dagger2和1比较,他们两个在很多方面都非常相似,但也有很重要的区别,如下:

  • 再也没有使用反射:图的验证、配置和预先设置都在编译的时候执行。
  • 容易调试和可跟踪:完全具体地调用提供和创建的堆栈
  • 更好的性能:谷歌声称他们提高了13%的处理性能
  • 代码混淆:使用派遣方法,就如同自己写的代码一样

当然所有这些很棒的特点都需要付出一个代价,那就是缺乏灵活性,例如:Dagger2没用反射所以没有动态机制。

Dagger2简单实用手册

Dagger2的详细官方文档可以在这里找到:http://google.github.io/dagger/,本章基本源于对官方文档的翻译,加上了部分自己的想法帮助大家更快理解框架内容

整个Dagger2框架是依赖于Java语言的注解(Annotation)系统实现的,在分析Espresso源码的过程中我们会遇到如下的注解:

  • @Inject
  • @Component
  • @Singleton
  • @Module
  • @Provides
  • @Subcomponent

@Inject注解

@Inject用于声明依赖,在类的构造函数上使用@Inject注解,声明该类可以被Dagger2实例化,同时如果该构造函数是带参数的,那么就会去使用使用了@Inject声明的构造函数生成一个实例传递进来。如示例代码中heater就会调用new Heater()方法生成一个Heater实例注入进来(Heater()方法已有@Inject注解)。特别要提到的是没有@Inject方法注解的类是无法被Dagger2框架实例化的:

class Thermosiphon implements Pump {
  private final Heater heater;

  @Inject
  Thermosiphon(Heater heater) {
    this.heater = heater;
  }

  ...
}

也可以直接对成员变量注入

class CoffeeMaker {
  @Inject Heater heater;
  @Inject Pump pump;

  ...
}

@Provides注解满足依赖

上文说到@Inject需要的依赖会自动调用构造方法,在有些情况下@Inject注解是无法生效的:

  • Interface是无法实例化的
  • 第三方库是无法添加注解的
  • 需要配置的对象在给定配置前的实例化是没有意义的

在这种情况下我们需要@Provides注解来满足依赖,带有这个注解的函数的返回类型就能满足该类型所需的实例化依赖。举个例子,前面的Heater()方法并没有提供注入接口,那么当我们需要一个Heater对象时,如下的方法也能够返回一个Heater对象:

@Provides Heater provideHeater() {
  return new ElectricHeater();
}

@Provides注解的方法也可以有自己的依赖,比如providePump方法就需要一个Thermosiphon类型的依赖:

@Provides Pump providePump(Thermosiphon pump) {
  return pump;
}

@Module注解依赖图容器

@Provides不是随处都能使用的,是需要在@Module注解标记的类内部才能生效的

@Module
class DripCoffeeModule {
  @Provides Heater provideHeater() {
    return new ElectricHeater();
  }

  @Provides Pump providePump(Thermosiphon pump) {
    return pump;
  }
}

@Component注解依赖图的根节点

前面我们提到Dagger2框架会自动生成代码来根据依赖图产生类的实例,比如在示例代码中:

@Component(modules = DripCoffeeModule.class)
interface CoffeeShop {
  CoffeeMaker maker();
}

@Component的modules参数声明了依赖Module,同时声明一个接口及接口方法,Dagger2框架会自动生成一个以Dagger为前缀的类继承实现这个接口,在本例中生成的类会命名为DaggerCoffeeShop,并实现maker()方法,实现的方式是一个CoffeeMaker类型的依赖,即调用者可以使用DaggerCoffeeShop().maker()方法来获得这个依赖。当然这个书写是有点问题的,为了让Dagger2框架帮我自动生成一个目标类的实例,需要调用create()方法,所以它的实现应该是这样的:

public class CoffeeApp {
  public static void main(String[] args) {
    CoffeeShop coffeeShop = DaggerCoffeeShop.create();
    coffeeShop.maker();
  }
}

@Subcomponent子Component注解

在@Component注解的接口类的方法中,除了可以返回注入项(实现了@Inject注解的构造方法的类,可以被Dagger2框架实例化)类别以外,还可以返回@Subcomponent注解的子Component类,以实现多层调用的效果,具体请看Espresso源码分析部分

@Singleton单例注解

这个注解是最好理解的,声明了这个注解的实例在生成实例时都是单例化的,如果之前以及生成过改类型的实例会直接返回之前生成的实例而不是新建一个该类的新的对象

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,176评论 5 469
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,190评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,232评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,953评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,879评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,177评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,626评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,295评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,436评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,365评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,414评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,096评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,685评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,771评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,987评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,438评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,032评论 2 341

推荐阅读更多精彩内容