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

时间: 2024-10-02 12:25:21

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

10分钟快速理解依赖注入

看到网络上很多"依赖注入"解释的话题,这篇博客呢也只是我自己的观点,如果你有不同的观点请拍砖,不用客气.业务场景 小明要去旅游,但是还未确定以什么方式出游,有可能是徒步旅行,也有可能是自驾游.代码演示 根据步行和驾车的速度来考虑距离旅游目的地的路程,所以这里定义了两个属性$speed和$distance.所有有了如下代码: interface travelInterface{ public function __construct($speed, $distance); public

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

最近闲来无事,突发奇想,也顺便练练手,于是就萌生了,能否用typescript的decorator写一个Nodejs SpringMVC,通过依赖注入,自动实现文件加载,实例化等.然后就有了这个项目. 该项目支持: 依赖注入Controller ,Service 注入GET/POST/PUT/DELETE/PATCH等rest方法 解析rest api的参数,例如RequestParam 上传文件支持Multer 支持在vscode里面直接debug typescript 的代码 想学习如何de

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

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

依赖注入利器 - Dagger ?

概述 声明需要注入的对象 如何实例化出依赖 Module的使用 Component的使用 Dagger的进阶使用 Components之间的关系 dependencies Subcomponents Scopes Singlton 自定义Scope scope的作用 Lazy注入 Provider注入 Qualifiers注入 编译时验证 小结 概述 在开发过程中,为了实现解耦,我们经常使用依赖注入,常见的依赖注入方式有: 构造方法注入:在构造方法中把依赖作为参数传递进去 setter方法注入:

浅析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/cd2c

[译]12-spring依赖注入

每个java应用程序都是由多个类协作才最终生成了终端用户所使用的系统.当编写复杂java应用程序的时,类之间应尽 可能保持独立,因为这样更容易做到代码的重用,也有利于单元测试的开展.spring的依赖注入功能能在保持类相互独立 的同时把他们"粘合"起来. 考虑如下场景:你的应用程序中有个文本编辑器组件,你现在想给你的文本编辑器添加拼写检查的功能.那么你可能写 出如下的代码来: public class TextEditor { private SpellChecker spellChe

开涛spring3(12.2) - 零配置 之 12.2 注解实现Bean依赖注入

12.2  注解实现Bean依赖注入 12.2.1  概述 注解实现Bean配置主要用来进行如依赖注入.生命周期回调方法定义等,不能消除XML文件中的Bean元数据定义,且基于XML配置中的依赖注入的数据将覆盖基于注解配置中的依赖注入的数据. Spring3的基于注解实现Bean依赖注入支持如下三种注解: Spring自带依赖注入注解: Spring自带的一套依赖注入注解: JSR-250注解:Java平台的公共注解,是Java EE 5规范之一,在JDK6中默认包含这些注解,从Spring2.

使用Roboguice依赖注入规划Android项目

关于依赖注入 Dependency Injection( 依赖注入)可以很好的帮助我们分离模块,降低耦合.提高可测试性.(PS:Roboguice 只是一个工具,依赖注入更多的是一种思想) 通常博主开发项目时喜欢以Activity .Service 等组件作为顶级层入口,辅以各类接口作为业务服务.Activity 主要负责维护界面相关的东西,及提供功能所需要的上下文环境,引入功能实现需要的接口. 这些接口的实例通过Roboguice进行注入.(当然你也可以完全不使用Roboguice,但还是建议

Spring-DI控制反转和IOC依赖注入

Spring-DI控制反转和IOC依赖注入 DI控制反转实例 IDEAJ自动导入Spring框架 创建UserDao.java接口 public interface UserDao { public void say(); } 创建UserDaoImpl.java继承UserDao.java并重写say()方法 public class UserDaoImpl implements UserDao{ @Override public void say() { System.out.println