Dagger:快速的依赖注入for 安卓&Java

2014年5月8日 星期四

15:29

官网: http://square.github.io/dagger/
GitHub: https://github.com/square/dagger

JavaDocs: http://square.github.io/dagger/javadoc/index.html

注:来自我的OneNote笔记,其实官网给的教程挺好的,最好下载GitHub上的例子来看

使用方法:

例子: coffee
example
.

声明依赖性:使用javax.inject.Inject注解。

注解构造方法:

class Thermosiphon implements Pump {

private final Heater heater;

@Inject

Thermosiphon(Heater
heater) {

this.heater = heater;

}

...

}

当然,Dagger支持直接注解成员变量:

class CoffeeMaker {

@Inject Heater heater;

@Inject Pump pump;

...

}

如果你的类有通过@Inject注解的成员变量,但是没有@Inject注解的构造方法,Dagger就会使用一个无参构造方法(如果存在的话)。

Dagger不支持方法注入

满足依赖关系:

默认情况下,Dagger满足依赖关系是通过调用构造方法得到的实例,比如如果要一个CoffeeMaker对象,Dagger就会调用new CoffeeMaker(),并且设置所有可注入的成员变量。

但是,下面的情况下,@Inject是不能用的:

  1. 接口
  2. 第三方的类
  3. 可配置的对象必须被配置。应该值得是那些经过配置才得到实例的类

这时候,我们就可以通过@providers,去注解一个方法来满足依赖。方法的返回类型就是依赖要满足的类型。

如通过provideHeater()来得到一个Heater:

@Provides Heater provideHeater() {

return new ElectricHeater();

}

也有可能@Providers方法必须依赖他自己:

@Provides Pump providePump(Thermosiphon pump) {

return pump;

}

所有的@Providers方法必须属于一个module,通过对一个类进行@Module注解来实现。

@Module

class DripCoffeeModule {

@Provides Heater provideHeater() {

return new ElectricHeater();

}

@Provides Pump providePump(Thermosiphon pump) {

return pump;

}

}

按照惯例 @Providers方法都会用provide作为前缀,@Module类都用Module作为后缀。

建立一个Graph

创建一个ObjectGraph对象的方法是调用create()并传入一个Module:

ObjectGraph objectGraph =
ObjectGraph.create(new
DripCoffeeModule());

为了使用,我们需要指定模块的注入对象类。这里我们将CoffeeApp作为开始的依赖注入类:

class CoffeeApp implements Runnable {

@Inject CoffeeMaker coffeeMaker;

@Override public void
run() {

coffeeMaker.brew();

}

public static void main(String[] args) {

ObjectGraph
objectGraph = ObjectGraph.create(new
DripCoffeeModule());

CoffeeApp coffeeApp =
objectGraph.get(CoffeeApp.class);

...

}

}

然后,我们配置@Module注解来注册之。

@Module(

injects = CoffeeApp.class

)

class DripCoffeeModule {

...

}

单例:@Singleton

//1. 标记方法

@Provides
@Singleton
Heater provideHeater() {

return new ElectricHeater();

}

//2. 标记类

@Singleton

class CoffeeMaker {

...

}

懒注入:Lazy类

class GridingCoffeeMaker {

@Inject Lazy<Grinder> lazyGrinder;

public void brew() {

while (needsGrinding()) {

//
调用get方法的时候Grinder的实例才被创建

lazyGrinder.get().grind();

}

}

}

Provider 注入:每次调用get都得到一个新的实例

class BigCoffeeMaker {

@Inject Provider<Filter> filterProvider;

public void brew(int
numberOfPots) {

...

for (int p = 0; p < numberOfPots; p++) {

maker.addFilter(filterProvider.get());
//new filter every time.

maker.addCoffee(...);

maker.percolate();

...

}

}

}

Qualifiers:限定符,通过限定符来得到不同限定符的实例

@Qualifier

@Documented

@Retention(RUNTIME)

public @interface Named {

String value() default "";

}

你可以创建自定义的Qualifier或者使用Named

class ExpensiveCoffeeMaker {

@Inject @Named("water") Heater waterHeater;

@Inject @Named("hot plate") Heater hotPlateHeater;

...

}

Qualifier也支持@Providers

@Provides @Named("hot plate") Heater provideHotPlateHeater() {

return new ElectricHeater(70);

}

@Provides
@Named("water") Heater provideWaterHeater()
{

return new ElectricHeater(93);

}

静态注入:谨慎使用,不好测试和重复使用

编译阶段的校验:

Dagger包含一个注解处理器来校验Modules和Injections,这个processor是严格的,所以如果你的dagger使用有误的话会导致编译器错误。例如下面这个问题会提示错误:

@Module

class DripCoffeeModule {

@Provides Heater provideHeater(Executor executor)
{

return new CpuHeater(executor);

}

}

编辑错误信息为:

[ERROR] COMPILATION ERROR :

[ERROR] error: No binding for
java.util.concurrent.Executor

required by provideHeater(java.util.concurrent.Executor)

解决办法是提供一个得到Executor的方法,并且用@Providers注解,或者标记该module的complete=false,意思是可以允许丢失的依赖:

@Module(complete = false)

class DripCoffeeModule {

@Provides Heater
provideHeater(Executor executor) {

return new CpuHeater(executor);

}

}

如果Module中提供了没有用到的注入也会报错,如:

@Module(injects = Example.class)

class DripCoffeeModule {

@Provides Heater
provideHeater() {

return new ElectricHeater();

}

@Provides Chiller
provideChiller() {

return new ElectricChiller();

}

}

因为Example类只用到了Heater,javac就会报错:

[ERROR] COMPILATION ERROR:

[ERROR]: Graph validation failed: You have these unused @Provider
methods:

1.
coffee.DripCoffeeModule.provideChiller()

Set
library=true in your module to
disable this check.

如果你的module有可能被injects 列表以外的类使用的话,可以标注module为一个library,方法如下:

@Module(

injects =
Example.class,

library = true

)

class DripCoffeeModule {

@Provides Heater
provideHeater() {

return new ElectricHeater();

}

@Provides Chiller
provideChiller() {

return new ElectricChiller();

}

}

我们可以创建一个模块,这个模块包含了所有其他的模块Module:

@Module(

includes =
{

DripCoffeeModule.class,

ExecutorModule.class

}

)

public class CoffeeAppModule {

}

Dagger的注解处理器会在编译的时候生成类似CoffeeMaker$InjectAdapter.java或者DripCoffeeModule$ModuleAdater这样的代码文件,这些文件是Dagger的实现。你不要直接使用他们,当然,Debug的时候,就很方便了。

Dagger会报错,如果一个依赖中包含多个同样的@Providers方法。但是有时候我们也需要这样做,比如在开发或者测试的时候,可以使用overvides=true标记Module来实现这一目的。

public class CoffeeMakerTest {

@Inject CoffeeMaker
coffeeMaker;

@Inject Heater heater;

@Before public void
setUp() {

ObjectGraph.create(new
TestModule()).inject(this);

}

@Module(

includes
= DripCoffeeModule.class,

injects
= CoffeeMakerTest.class,

overrides
= true

)

static class TestModule
{

@Provides
@Singleton Heater provideHeater() {

return Mockito.mock(Heater.class);

}

}

@Test public void
testHeaterIsTurnedOnAndThenOff() {

Mockito.when(heater.isHot()).thenReturn(true);

coffeeMaker.brew();

Mockito.verify(heater,
Mockito.times(1)).on();

Mockito.verify(heater,
Mockito.times(1)).off();

}

}

重写在下面这样的情景很适合用:

单元测试时,用一个模拟的实现替换一个真是的实现

在开发时,用一个模拟的认证替换一个真实的认证。

集成方法:

Maven:

<dependency>

<groupId>com.squareup.dagger</groupId>

<artifactId>dagger</artifactId>

<version>(insert latest version)</version>

</dependency>

<dependency>

<groupId>com.squareup.dagger</groupId>

<artifactId>dagger-compiler</artifactId>

<version>(insert latest version)</version>

<optional>true</optional>

</dependency>

Gradle类似,语法是 compile "groupId:artifactId:version"

Dagger:快速的依赖注入for 安卓&Java的更多相关文章

  1. [Android]使用Dagger 2进行依赖注入 - Producers(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6234811.html 使用Dagger 2进行依赖注入 - P ...

  2. 放弃dagger?Anrdoi依赖注入框架koin

    Koin 是什么 Koin 是为 Kotlin 开发者提供的一个实用型轻量级依赖注入框架,采用纯 Kotlin 语言编写而成,仅使用功能解析,无代理.无代码生成.无反射. 官网地址 优势 依赖注入好处 ...

  3. 用Decorator实现依赖注入,像Java一样写后台

    最近闲来无事,突发奇想,也顺便练练手,于是就萌生了,能否用typescript的decorator写一个Nodejs SpringMVC,通过依赖注入,自动实现文件加载,实例化等.然后就有了这个项目. ...

  4. 使用 .NETCore自带框架快速实现依赖注入

    Startup 在Startup的ConfigureServices()中配置DI的接口与其实现 public void ConfigureServices(IServiceCollection se ...

  5. [Android]使用Dagger 2依赖注入 - DI介绍(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5092083.html 使用Dagger 2依赖注入 - DI介 ...

  6. [Android]使用Dagger 2依赖注入 - API(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5092525.html 使用Dagger 2依赖注入 - API ...

  7. [Android]使用Dagger 2依赖注入 - 自定义Scope(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5095426.html 使用Dagger 2依赖注入 - 自定义 ...

  8. [Android]使用Dagger 2依赖注入 - 图表创建的性能(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5098943.html 使用Dagger 2依赖注入 - 图表创 ...

  9. Android 和 Dagger 2 中的依赖注入

    原文:Dependency Injection in Android with Dagger 2 作者:Joe Howard 译者:kmyhy 在现代开发团队中到处充斥着"你一定要用依赖注入 ...

随机推荐

  1. luoguP5105 不强制在线的动态快速排序

    emm 可重集合没用用.直接变成不可重复集合 有若干个区间 每个区间形如[L,R] [L,R]计算的话,就是若干个连续奇数的和.拆位统计1的个数 平衡树维护 加入一个[L,R],把相交的区间合并.之后 ...

  2. mysql数据库----python操作mysql ------pymysql和SQLAchemy

    本篇对于Python操作MySQL主要使用两种方式: 原生模块 pymsql ORM框架 SQLAchemy 一.pymysql pymsql是Python中操作MySQL的模块,其使用方法和MySQ ...

  3. MATLAB2010安装方法

    MATLAB2010安装方法 第一步选择无网络安装. 选择yes,然后点击next 激活序列号在crack文件夹中的txt文档中 这一步按照图片上的显示操作就可以 选择经典安装 按提示操作,这一步事激 ...

  4. js通过生成临时表单再删除的方式向后台提交数据(模拟ajax的post提交但还要跳转页面不返回数据)以及 struts向前台返回文件下载及防止中文乱码处理

    为了避免发送数据中有特殊字符,发送时用 encodeURIComponent 编码 (其实这个 if中是直接通过浏览器下载文件的方法,else是向后台传数据的方法) struts后台Action处理接 ...

  5. UESTC--1300

    原题链接:http://acm.uestc.edu.cn/problem.php?pid=1300 分析:dp,最长公共上升子列.对于两个序列num1[maxn],num2[maxn]: 如果num1 ...

  6. 使用OAuth2.0协议的github、QQ、weibo第三方登录接入总结

    目录 第三方接入总结 OAuth2.0介绍 github OAuth2.0登录接入 国内第三方应用商SDK使用 微博SDK 腾讯QQ SDK passport.js插件使用 安装 相关中间件.路由 返 ...

  7. centos7通过yum安装MySQL

    一:去官网查看最新安装包 https://dev.mysql.com/downloads/repo/yum/ 二:下载MySQL源安装包 wget http://dev.mysql.com/get/m ...

  8. 基础知识:BT1120

    今天谈点我所理解的BT1120协议. BT1120是高清晰度电视 (HDTV) 演播室信号数字接口,首先说一下接口标准里面的概念,然后谈谈自己的理解,写这个文章的目的就是解释给自己听的,所以都是一些白 ...

  9. JavaScript 数组操作:slice vs splice

    在 JavaScript 中,对于数组的操作有两个很容易混淆的方法 splice, slice ,这里给大家推荐一篇介绍 splice, slice 二者区别的文章. In JavaScript, m ...

  10. 引用类型 ( 对象定义 )——Array 类型

    本文地址:http://www.cnblogs.com/veinyin/p/7607293.html  一个数组中可以存储不同类型的值,可以混合存储数字.字符串.对象等 1 创建数组 1.1 构造函数 ...