Dagger

依赖注入的诉求, 这边就不重复描述了, 在上文Spring以及Guice的IOC文档中都有提及, 既然有了Guice,

Google为啥还要搞个Dagger2出来重复造轮子呢? 因为使用动态注入, 虽然写法简单了, 耦合也降低了,

但是带来了调试不方便, 反射性能差等一些缺点.

而Dagger跟Guice最大的差异在于, 他是编译期注入的, 而不是运行时.

他生成的代码可以直观的调试, 也不是通过反射, 而是通过构建工厂类. 下面我们用代码来简单演示一下.

构建工程

既然Dagger是静态注入的, 那么他自然也跟其他动态注入框架工程有点区别,

编译时需要额外依赖dagger-compiler, dagger-producers等,

不过运行时的jar只需要dagger以及javax.inject包即可.

好在Google为我们提供了pom文件, 我们只需要在idea里新建maven工程, 在pom文件中导入如下内容, 他会自动下载依赖.

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.maven.dagger2</groupId>
<artifactId>com.maven.dagger2</artifactId>
<version>1.0-SNAPSHOT</version> <dependencies>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>2.2</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

第一个注入程序

我们以一个打印系统为例, 打印业务类PrintJob, 里面有一份报表Reportpage待打印.

 public class ReportPage{

     public void print(){
System.out.println("开始打印报表");
}
}
 public class PrintJob {
2  // 需要打印的报表
public ReportPage reportPage; public void setReportPage(ReportPage reportPage) {
this.reportPage = reportPage;
} public void print() {
this.reportPage.print();
} public static void main(String[] args) throws InterruptedException {
// 初始化报表
ReportPage page = new ReportPage();
PrintJob job = new PrintJob();
job.setReportPage(page);
//执行打印
job.print();
}
}

在main函数中, 我们初始化了Printjob以及它里面的报表对象, 并执行打印.

下面我们通过Dagger注入的方式来写.

写法很简单, 跟Guice类似, 我们只需要在reportpage成员上加@Inject注解.

同时添加一个Component对象, 用来告诉Dagger, 应该注入到该类, 并扫描其中@Inject的成员

 @Component
public interface PrintjobComponent { void inject(PrintJob job);
}

添加完Component以及@Inject注解后我们需要编译代码或者rebuild工程, 让Dagger为我们生成工厂类.

生成的代码位于target/generated-sources目录. 里面会有一个叫DaggerPrintjobComponent的类.

idea会自动将当期路径标记成Classpath, 因此我们也不需要把他手动拷贝出来.

如果没有自动import, 可以右键pom.xml->Maven ->Reimport.

我们在Printjob的构造函数里加上DaggerPrintjobComponent.create().inject(this);来实现注入

 public class PrintJob {

     @Inject
public ReportPage reportPage; public PrintJob() {
DaggerPrintjobComponent.create().inject(this);
} public void print() {
this.reportPage.print();
} public static void main(String[] args) throws InterruptedException {
// 看上去清爽了一点
PrintJob job = new PrintJob();
job.print();
}
}
 public class ReportPage {

     @Inject
public ReportPage() {
System.out.println("初始化成功!!!");
} public void print(){
System.out.println("开始打印报表");
}
}

相比于一开始的非注入写法, 在外部是看不到赋值操作的.

有人会说, 那我直接在printjob的构造函数里new reportpage()不就行了, 为什么要这么费事呢.

原因很简单, 大型系统里, printjob只存在一个接口, 他无法, 也不需要直接new reportpage()对象.

下面演示如何注入接口对象.

注入接口对象

我们给reportpage增加一个接口, 并在printjob中修改为接口声明.

 public class ReportPage implements ReportPageProvider{
 public interface ReportPageProvider {

     void print();
}
 public class PrintJob {

     @Inject
public ReportPageProvider reportPage;

这个时候会发现, 运行注入报错了, 原因很简单, 我们@inject依然加载reportpage对象上,

此时他是一个接口, 接口是无法直接被实例化的.

因此我们需要引入Module对象来处理接口, 其实就是类似于一个工厂提供类.

 @Module
public class ReportPageModule { @Provides
public ReportPageProvider createPage() {
return new ReportPage();
}
}

然后在component中引入module, 其他代码不用改, 依然直接new printjob().print()对象.

 @Component(modules = ReportPageModule.class)
public interface PrintjobComponent { void inject(PrintJob job);
}

接口存在多个实现

我们给ReportpageProvider再增加一个子类NewReportPage, 修改Module, 增加一个方法, 构造NewReportPage.

 @Module
public class ReportPageModule { @Provides
public ReportPageProvider createPage() {
return new ReportPage();
} @Provides
public ReportPageProvider createNewReportPage() {
return new NewReportPage();
} }

这个时候直接编译是无法通过的, 相同返回类型的provider只能添加一个, 如果添加多个, dagger将报错, 存在多个提供类.

此时我们就要跟Guice里一样, 使用@Named注解来标识了

     @Named("new")
public ReportPageProvider reportPage;

调用的时候也很简单

     @Inject
@Named("new")
public ReportPageProvider reportPage;

同理, 也可以通过@Qualifier来自定义注解标识.

 @Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface NewReportMark {}

然后在调用的地方加上 @NewReportMark即可.

Scope生命周期

默认对象都是每次都new的, 如果想要单例实现, 则需要添加@Singleton.

在Component以及Module都加上Singleton注解.

 @Singleton
@Component(modules = ReportPageModule.class)
public interface PrintjobComponent { void inject(PrintJob job);
}
     @Provides
@Named("new")
@Singleton
public ReportPageProvider createNewReportPage() {
return new NewReportPage();
}

我们给Printjob中再增加一个reportpage对象, 并打印他们的hashcode.

     @Inject
@Named("new")
public ReportPageProvider reportPage; @Inject
@Named("new")
public ReportPageProvider reportPage2; ...... PrintJob job = new PrintJob();
System.out.println(job.reportPage);
System.out.println(job.reportPage2);

加上Singleton注解后, 打印出来的hashcode是一致的了.

但是, 如果我们再new 一个Printjob, 打印他的reportpage.

         PrintJob job = new PrintJob();
System.out.println(job.reportPage);
System.out.println(job.reportPage2); PrintJob job2 = new PrintJob();
System.out.println(job2.reportPage);
System.out.println(job2.reportPage2);

会发现前两个的hashcode跟后两个的不一样, 这就很蛋疼了. 他只是一个作用于当前component的伪单例.

那么如何实现真单例呢, 其实就是想办法把Component搞成单例的.

这样他里面的对象也都是同一个作用域下的单例了.

我们添加一个SingletonPrintjobComponent, 写法与PrintjobComponent一致.

编译后生成DaggerSingletonPrintjobComponent. 然后修改printjob构造函数中的注入.

DaggerPrintjobComponent.create().inject(this); 改成如下:

 public class PrintJob {

     private static SingletonPrintjobComponent component = DaggerSingletonPrintjobComponent.create();

     @Inject
@Named("new")
public ReportPageProvider reportPage; @Inject
@Named("new")
public ReportPageProvider reportPage2; public PrintJob() {
component.inject(this);
} public void print() {
this.reportPage.print();
} public static void main(String[] args) throws InterruptedException {
PrintJob job = new PrintJob();
System.out.println(job.reportPage);
System.out.println(job.reportPage2); PrintJob job2 = new PrintJob();
System.out.println(job2.reportPage);
System.out.println(job2.reportPage2);
}
}

这样的话, 多个printjob打印出来的reportpage就是一致的了, 因为都是位于同一个static的component中.

Lazy 延迟初始化

默认对象是inject的时候初始化, 如果使用Lazy封装一下, 则可以在get的时候再初始化.

     @Inject
@Named("old")
public Lazy<ReportPageProvider> oldReportPage;
         PrintJob job = new PrintJob();
Thread.sleep(3000);
// 对象会在get()方法调用的时候触发初始化
job.oldReportPage.get().print();

到这边就结束了, 可以看到Dagger使用上跟Guice基本差不多, 各个注解概念也类似,

最大的区别就是非动态注入, 非反射实现, 而是编译期静态注入.

使用Dagger2做静态注入, 对比Guice.的更多相关文章

  1. Android项目使用Dagger2进行依赖注入

    原文链接:http://code.tutsplus.com/tutorials/dependency-injection-with-dagger-2-on-android–cms-23345 依赖注入 ...

  2. Spring静态注入的三种方式

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/chen1403876161/article/details/53644024Spring静态注入的三 ...

  3. spring 静态注入

    1.静态注入 在setter 方法修改为非 static , 然后在上面注入即可 @Component public class WeixinConfig { // token public stat ...

  4. 日志系统实战(一)—AOP静态注入

    背景 近期在写日志系统,需要在运行时在函数内注入日志记录,并附带函数信息,这时就想到用Aop注入的方式. AOP分动态注入和静态注入两种注入的方式. 动态注入方式 利用Remoting的Context ...

  5. 基于Mono.Cecil的静态注入

    Aop注入有2种方式:动态注入和静态注入,其中动态注入有很多实现了 动态注入有几种方式: 利用Remoting的ContextBoundObject或MarshalByRefObject. 动态代理( ...

  6. Android 使用dagger2进行依赖注入(基础篇)

    0. 前言 Dagger2是首个使用生成代码实现完整依赖注入的框架,极大减少了使用者的编码负担,本文主要介绍如何使用dagger2进行依赖注入.如果你不还不了解依赖注入,请看这一篇. 1. 简单的依赖 ...

  7. 用keras做SQL注入攻击的判断

    本文是通过深度学习框架keras来做SQL注入特征识别, 不过虽然用了keras,但是大部分还是普通的神经网络,只是外加了一些规则化.dropout层(随着深度学习出现的层). 基本思路就是喂入一堆数 ...

  8. spring静态注入

    与其说是静态注入(IOC),不如讲是对JavaBean 的静态成员变量进行赋值. 一般我们在使用依赖注入的时候,如果当前对象(javaBean )创建(实例化)一次,那么非静态的成员变量也会实例化一次 ...

  9. 转: spring静态注入

    与其说是静态注入(IOC),不如讲是对JavaBean 的静态成员变量进行赋值. 一般我们在使用依赖注入的时候,如果当前对象(javaBean )创建(实例化)一次,那么非静态的成员变量也会实例化一次 ...

随机推荐

  1. js之学习正则表达式

    看了掘金的一个作者写的JS正则表达式完整教程 受益匪浅,感谢作者的无私奉献.在此,做下笔记. 目录 0. 目录 1. 正则表达式字符匹配 1.1.字符组 1.2.量词 1.3.多选分支 1.4.案例分 ...

  2. AngularJS学习篇(一)

    AngularJS 使用 表达式 把数据绑定到 HTML. AngularJS 表达式 AngularJS 表达式写在双大括号内:{{ expression }}. AngularJS 表达式把数据绑 ...

  3. zepto在操作dom的selected和checked属性时尽量使用prop方法

    zepto在操作dom的selected和checked属性时尽量使用prop方法.

  4. redhat7 Samba

    1.先安装Samba服务 yum install -y samba samba-client 2.配置文件 vi /etc/samba/smb.conf  --主配置文件 [global]  --全局 ...

  5. Javascript 内核Bug

    Javascript 内核Bug: js 执行(9.9+19.8)加法运算 等于 29.700000000000003) <html> <head> <title> ...

  6. JS-类型转换

    类型转换 值 转字符串 数字 布尔值 对象 undefined 'undefined' 0 false throws TypeError null 'null' 0 false throws Type ...

  7. 实现基于Keepalived高可用集群网站架构的多种方法

    实现基于Keepalived高可用集群网站架构 随着业务的发展,网站的访问量越来越大,网站访问量已经从原来的1000QPS,变为3000QPS,目前业务已经通过集群LVS架构可做到随时拓展,后端节点已 ...

  8. 对于ES6中Promise的个人见解

    1.js中常见的异步 JavaScript可以响应用户的一些异步交互,比如单击鼠标和按键盘等操作. let button = document.getElementById("btn&quo ...

  9. 如何将FastReportOnlineDesign 灵活的应用到C/S B/S 程序当中?

    一.好久没有写博客了,主要是停在这里太久了,有些事情让自己尽量不在去想,忘记不了一段难以忘怀的记忆,就让这一段美好的记忆沉没在无锡的太湖中吧!不在去想了.难以忘怀..... 二.废话不多说了,不如正题 ...

  10. 新的开始,hello world!

    开始使用博客一年多来,在各位大神的博客上找了很多学习需要的资料,受益匪浅.一直来自己也想过开始写自己的博客,但是一直没有开始.一来是懒,懒的整理,懒的打字排版,二来是那段时间加入实验室,自我感觉一直有 ...