这可能是最详细的 Dagger2 使用教程 二(限定注解 @Named、@Qulifier 和 范围注解 @Singleton、@Scope)

通过上一篇文章我们知道了 Dagger2 的基本使用,在这篇文章中,我们将讲解 Dagger 中的两个重要概念以及相关注解。

这可能是最详细的 Dagger2 使用教程 一(基本使用)

类型上再加限定:@Named 和 @Qulifier 注解的使用

通过上面的例子,我们已经学习了 Dagger 的基本的用法,张三也可以获取到电脑来玩游戏了。不过这个时候,张三吃着火锅唱着歌,玩着游戏喝着可乐,脑子里灵光一闪,觉得这个台式机玩游戏爽是爽,但是不能携带啊,自己这么高的段位好歹也要把电脑拿到星巴克给别人展示啊。简单来说,张三想把自己的台式机换成游戏本了。

那张三的这个需求咱们怎么满足,根据上面的说法,游戏本也能在淘宝上找到啊,那我们就直接修改 Taobao 这个依赖供应商,添加一个获取游戏本的方法:

@Module
public class TaoBao {@Providespublic Computer getDesktop(CPU cpu) {return new Computer("淘宝的台式机", cpu);}@Providespublic Computer getNotebook(CPU cpu) {return new Computer("淘宝的笔记本", cpu);}//......
}

看似很完美,这下 Taobao 这个供应商既能供应台式机,又能供应笔记本了。现在编译一下代码:

demo/src/main/java/lic/swift/demo/dagger/ZTOExpress.java:6: 错误: [Dagger/DuplicateBindings] lic.swift.demo.dagger.Computer is bound multiple times:
public interface ZTOExpress {^@Provides lic.swift.demo.dagger.Computer lic.swift.demo.dagger.TaoBao.getComputer(lic.swift.demo.dagger.CPU)@Provides lic.swift.demo.dagger.Computer lic.swift.demo.dagger.TaoBao.getNotebook(lic.swift.demo.dagger.CPU)lic.swift.demo.dagger.Computer is injected atlic.swift.demo.dagger.Person.computerlic.swift.demo.dagger.Person is injected atlic.swift.demo.dagger.ZTOExpress.deliverTo(lic.swift.demo.dagger.Person)

出错了,Dagger 显示 Computer 这个类被绑定了多次。为什么会出现这种情况呢?那是因为 Dagger 是通过函数的返回值类型来判断应该调用哪个方法获取依赖对象的,你这两个方法虽然函数名不一样,但是返回值类型都是一样的,在这种情况下 Dagger 需要获取一个 Computer 但它是不知道应该调用哪个方法来获取 Computer 的。

这个时候,就需要使用 @Named 注解了,这个注解使 Dagger 可以在返回值类型一样的情况下,再继续判断 @Named 注解的 value 值。现在继续修改 Taobao 这个供应商:

@Module
public class TaoBao {@Provides@Named("台式机")public Computer getDesktop(CPU cpu) {return new Computer("淘宝的台式机", cpu);}@Provides@Named("笔记本")public Computer getNotebook(CPU cpu) {return new Computer("淘宝的笔记本", cpu);}//......
}

现在,通过 @Named 注解可以看到 getDesktop 返回的是 台式机 ComputergetNotebook 返回的是 笔记本 Computer

依赖供应方这边搞定了,那作为依赖需求方的张三,肯定要说明一下,你要的是什么类型的电脑了,是台式机还是笔记本,那怎么说明呢,很简单,只需要在 @Inject 的成员上再加上 @Named

public class Person {@Inject@Named("笔记本")        //告诉 Dagger 需要的是笔记本电脑Computer computer;//......
}

跑一下看看结果:

System.out                I  张三
System.out                I      使用 淘宝的笔记本(AMD CPU) 玩 赛博朋克2077

完美。现在张三可以拿着笔记本去星巴克打游戏了。而咱们也理解了 @Named 这个注解的用法了,简单来说,加上这个注解之后,Dagger 在判断类型时也会把这个注解带上进行判断。

那我们再想一想,为什么 @Named 这个注解这么牛呢?它是怎么实现的?

这个问题问得好!现在就该为大家介绍另外的一个注解 @Qulifier

qulifier 这个单词在英语中就是限定器的意思,顾名思义,在 Dagger 里肯定就是在类型相同时再进一步做个限定。它是一个元注解,@Named 就是继承于它。那我们怎么用这个注解呢?答案就是像 @Named 一样,自定义一个注解继承 @Qualifier

现在我们使用 @Qulifier 实现与上面相同的功能,先定义两个元注解分别表示台式机和笔记本:

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

然后,在代码中,替换上面使用 @Named 的地方。将 @Named("台式机") 替换为 @DesktopComputer,将 @Named(“笔记本”) 替换为 @NotebookComputer,其他地方不变。

在这么修改之后,你会发现代码跑起来的效果是一样的。这里就不啰嗦了。

另外还需要说明的是,像这种类型限定的注解 @Qulifier,不仅仅可以标记在函数返回值和成员变量上,其实还可以标记在函数的参数上。这一点咱们后面再演示。

创建范围内的单例:@Singleton@Scope 注解

我们在开发中,单例模式肯定是不少用的,但是大家可能不知道使用 Dagger 也能用来实现单例模式。这个特性得益于 Dagger 中范围的这个概念,也就是 @Scope 注解。这里说一下 Dagger 这个范围是啥意思,再演示怎么使用。简单来说,就是 Dagger 可以定义一个某某范围,在这个某某范围内,不会创建多个依赖对象,而是仅创建一个。

在上面的例子中,张三可以在外面用笔记本电脑玩游戏,也可以在家里用台式机玩游戏,但是这有一个问题。现在游戏那么大,动不动就几十个G,在家里还好说,那出门了再下载个游戏岂不是费死劲。流量贵不说,那网速是自从搞5G之后就下降了不少,这要把游戏下载下来,等到星巴克打烊也难说。那怎么整呢?硬盘啊,4G之前不就是通过移动硬盘来拷贝游戏的么。这里张三把游戏装到移动硬盘里不就行了,走到哪儿都可以用。

这里我们假设电脑都是依赖于这个硬盘,那么无论是台式机还是笔记本,都应该是依赖于同一个硬盘,如果不是,那就是张三把游戏安装错了,安装到系统盘里了。

咱们先给 Computer 类添加一个 Hardware 的依赖对象:

public class HardDisk {private String name;public HardDisk(String name) {this.name = name;}@Overridepublic String toString() {            //这里我们打印了地址return name + " 硬盘@" + Integer.toHexString(hashCode());}
}

修改一下 Computer 类:

public class Computer {private String name;private CPU cpu;private HardDisk hardDisk;        //电脑的硬盘public Computer(String name, CPU cpu, HardDisk hardDisk) {this.name = name;this.cpu = cpu;this.hardDisk = hardDisk;}public void play(String game) {System.out.println("使用 " + name + "(" + cpu + "," + hardDisk + ") 玩 " + game);}
}

现在 Computer 是依赖需求方,已经搞定了,在做完这些之后,那就要处理依赖供应方,依赖供应方是谁呢,那肯定是淘宝啊:

@Module
public class TaoBao {@Providespublic CPU getCPU() {return new CPU("AMD");}@Providespublic HardDisk getHardDisk() {return new HardDisk("希捷");}@Provides@DesktopComputerpublic Computer getDesktop(CPU cpu, HardDisk hardDisk) {return new Computer("淘宝的台式机", cpu, hardDisk);}@Provides@NotebookComputerpublic Computer getNotebook(CPU cpu, HardDisk hardDisk) {return new Computer("淘宝的笔记本", cpu, hardDisk);}
}

依赖提供方也搞定了,那依赖注入器需要修改吗?这个问题是值得想一想的。

答案是不需要,如果需要的话,就体现不出来 Dagger 的优势了。前面也说过,Dagger 在创建依赖对象的时候,是一个递归的过程。在这里 Dagger 只是为 Person 进行依赖注入,但是在注入 Computer 的时候发现创建 Computer 还需要 CPU,那 Dagger 就先去创建 CPU 这个依赖对象,然后发现还需要 HardDisk 对象,那就再去找,两个都找到了,才能创建出来一个 Computer ,然后将这个 Computer 注入给 Person 对象。因此依赖注入器是不需要修改的。

但是我们这里修改一下 Person 让这个类在玩游戏时能够显示持有的电脑是否使用相同的硬盘:

public class Person {@Inject@DesktopComputerComputer desktop;@Inject@NotebookComputerComputer notebook;public void playGame(String gameName) {System.out.print(name + "\n");desktop.play("\t" + gameName);notebook.play("\t" + gameName);}//......
}

这里我们想前面使用 Computer 一样使用 HardDisk ,这个时候应该用的不是同一个硬盘:

System.out                I  张三
System.out                I      使用 淘宝的台式机(AMD CPU,希捷 硬盘 @504f62) 玩     赛博朋克2077
System.out                I      使用 淘宝的笔记本(AMD CPU,希捷 硬盘 @22dd8f3) 玩     赛博朋克2077

可以看到两个硬盘的内存地址是不同的,这是两个不同的硬盘。 那怎么让两台电脑使用相同的硬盘呢?最简单的方式就是添加 @Singleton 注解。

首先就是需要在依赖供应方的相关方法上添加这个注解,这里就是 Taobao.getHardDisk() 方法:

@Provides
@Singleton
public HardDisk getHardDisk() {return new HardDisk("希捷");
}

在没有添加这个注解之前,当注入器发现需要这个类型的依赖,就会调用一次这个方法,这会创建一个全新的对象。就像我们到淘宝商城上买东西一样,买回来的当然是新的。但是添加了这个注解后,就相当于淘宝这个依赖供应方说明了,这个类型的对象,在这个范围里只有一个,谁来用就拿给谁,都是同一个。在这个例子中,就可以想象为这个硬盘是张三专属的范围,张三只有一个硬盘,只能获取到这一个。

其次,还需要在依赖注入器上添加这个注解:

@Singleton
@Component(modules = {TaoBao.class})
public interface ZTOExpress {void deliverTo(Person person);
}

为什么需要在依赖注入器上也添加这个范围呢?大家可以这么理解,这个中通可以配送淘宝上的任何东西(@Provides 方法),但现在淘宝上有个专属于张三的东西,你既然说都指定了供应方为淘宝(modules = {TaoBao.class}),那是不是淘宝上的所有范围的东西都能配送。既然如此你也得声明一下,以表示你可以配送这个范围内的东西。要不默认情况下,大家都会觉得你不能进行特殊范围的物品的配送的。

而在代码层面,这个注解的意义就在于:Dagger 在同一个作用范围内,@Provide 方法提供的依赖对象就会变成单例,也就是说依赖需求方不管依赖几次 @Provide 方法提供的依赖对象,Dagger 都只会调用一次这个方法。

下面我们跑起来,看看结果:

System.out                I  张三
System.out                I      使用 淘宝的台式机(AMD CPU,希捷 硬盘 @504f62) 玩     赛博朋克2077
System.out                I      使用 淘宝的笔记本(AMD CPU,希捷 硬盘 @504f62) 玩     赛博朋克2077

可以看到是使用的相同的硬盘。这就是 @Singleton 注解的作用。在这里就表示,通过中通从淘宝上拿到的硬盘都是这一块。但是这样也不太对,中通肯定不止为张三配送,那它为李四配送的时候,岂不是也送的张三的硬盘?

所以这时候就别用自带的 @Singleton 范围,而是自定义一个范围,也就是使用 @Scope 注解。现在我们就为张三创建一个专属的范围,通过这个例子咱们也会明白 @Scope 的使用了:

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface SanScope {
}

这里使用了 @Scope 这个元注解创建了张三专属范围,现在我们用这个注解替换前面的 @Singleton 注解。你会发现结果是一样的,这里就展示了。

在一般 Android 开发中,往往会创建诸如 @PerActivity@PerFragment 这样的范围注解。例如某些个 Activity 中的依赖的对象应该是相同的,即会用到 @PerActivity

在使用 @Scope 范围注解时,一定要注意两点:

  • 如果是通过依赖对象的构造函数创建依赖时,需要在类名上添加范围注解,不能在构造函数上添加,否则无效。
  • 范围内单例的前提是使用了相同的依赖注入器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/376549.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

罗技K380无线键盘及鼠标:智慧互联,一触即通

目录 1. 背景2. K380无线键盘连接电脑2.1 键盘准备工作2.2 电脑配置键盘的连接 3. 无线鼠标的连接3.1 鼠标准备工作3.2 电脑配置鼠标的连接 1. 背景 有一阵子经常使用 ipad,但是对于我这个习惯于键盘打字的人来说,慢慢在 ipad 上打字,实在是…

北摩高科应邀参加空客供应商大会

民航市场一直以来都是北摩高科重要的战略发展方向,进入国际航空巨头供应链体系也是公司的长期愿景。7月9日至10日,北摩高科公司应邀参与空客集团在天津举办的供应商大会及晚宴。 图1:空客集团采购总监Juergen Westermeier与北摩高科领导 会上…

基于Java+SpringMvc+Vue技术的药品进销存仓库管理系统设计与实现系统(源码+LW+部署讲解)

注:每个学校每个老师对论文的格式要求不一样,故本论文只供参考,本论文页数达到60页以上,字数在6000及以上。 基于JavaSpringMvcVue技术的在线学习交流平台设计与实现 目录 第一章 绪论 1.1 研究背景 1.2 研究现状 1.3 研究内容…

Linux权限相关

目录 Linux中的用户 Linux权限管理 Linux的文件访问者分类 Linux的文件类型和访问权限 文件类型 文件权限 文件权限的修改 文件所有者修改 文件所有者所在组修改 目录权限 粘滞位 文件掩码 在Linux中,权限包括用户的权限和文件的权限 Linux中的用户 在…

jenkins系列-06.harbor

https://github.com/goharbor/harbor/releases?page2 https://github.com/goharbor/harbor/releases/download/v2.3.4/harbor-offline-installer-v2.3.4.tgz harbor官网:https://goharbor.io/ 点击 Download now 链接,会自动跳转到上述github页面&am…

t-SNE降维可视化并生成excel文件使用其他画图软件美化

t-sne t-SNE(t-分布随机邻域嵌入,t-distributed Stochastic Neighbor Embedding)是由 Laurens van der Maaten 和 Geoffrey Hinton 于 2008 年提出的一种非线性降维技术。它特别适合用于高维数据的可视化。t-SNE 的主要目标是将高维数据映射…

Milvus核心设计(2)-----TSO机制详解

目录 背景 动机 Timestamp种类及使用场景 Guarantee timestamp Service timestamp Graceful time Timestamp同步机制 主流程 时间戳同步流程 背景 Milvus 在设计上突出了分布式的设计,虽然Chroma 也支持分布式的store 与 query。但是相对Milvus来说,不算非常突出。…

LabVIEW心电信号自动测试系统

开发了一种基于LabVIEW的心电信号自动测试系统,通过LabVIEW开发的上位机软件,实现对心电信号的实时采集、分析和自动化测试。系统包括心电信号采集模块、信号处理模块和自动化测试模块,能够高效、准确地完成心电信号的测量与分析。 硬件系统…

Vue3 markRaw的使用

markRaw 作用:将一个对象标记为不可以被转化为代理对象。返回该对象本身。 应用场景: 1.有些值不应被设置成响应式时,例如复杂的第三方类库等 2.当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能 3.在动态渲染组件的时候我们就可以使用 markRaw 包裹。markRaw 的…

秋招突击——7/9——MySQL索引的使用

文章目录 引言正文B站网课索引基础创建索引如何在一个表中查看索引为字符串建立索引全文索引复合索引复合索引中的排序问题索引失效的情况使用索引进行排序覆盖索引维护索引 数据库基础——文档资料学习整理创建索引删除索引创建唯一索引索引提示复合索引聚集索引索引基数字符串…

git 笔记

文章目录 前言一些代码托管仓库初步的一些理解设置个人信息创建自己的仓库查看仓库的状态添加文件到暂存区把暂存区的文件添加到版本库查询两个文件之间的区别查看版本迭代信息版本回滚查看所有的历史版本快捷切换应用感受分支的一些相关的操作假设新建一个分支并跳转到这个分支…

【ARM】MDK安装ARM_compiler5无法打开安装程序

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 在客户安装了最新版本的MDK5.37及后续更新版本,但原工程使用ARM_Compiler_5.06进行编译和调试,需安装ARM_Compiler_5.06的编译器版本,但在解压缩的过程中后续无法打开ARM_Compiler…

FinalShell介绍,安装与应用

目录 一、什么是finalshell 二、finalshell功能 三、为什么要用finalshell 四、安装finalshell 五、finalshell使用 1.添加连接 获取虚拟ip地址 2.启动连接 一、什么是finalshell FinalShell是一体化的的服务器,网络管理软件,不仅是ssh客户端,还是功能强大的开发,运维工…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(四)-无人机系统(UAS)命令与控制(C2)通信用例

引言 本文是3GPP TR 22.829 V17.1.0技术报告,专注于无人机(UAV)在3GPP系统中的增强支持。文章提出了多个无人机应用场景,分析了相应的能力要求,并建议了新的服务级别要求和关键性能指标(KPIs)。…

Re:从零开始的C++世界——(一)入门基础

文章目录 C发展历史1.命名空间1.1 namespace的价值1.2 namespace的定义1.3 命名空间使⽤ 2.C输⼊&输出3.缺省参数3.1 缺省参数的概念3.2 缺省参数的分类 4.函数重载5.引⽤5.1引⽤的概念和定义5.2 引⽤的特性5.3 const引⽤5.4 使用场景5.5 指针和引⽤的关系 6.内联函数6.1内…

NAT地址转换+多出口智能选路,附加实验内容

本章主要讲:基于目标IP、双向地址的转换 注意:基于目标NAT进行转换 ---基于目标IP进行地址转换一般是应用在服务器端口映射; NAT的基础知识 1、服务器映射 服务器映射是基于目标端口进行转换,同时端口号也可以进行修改&…

Mybatis-plus 集成 PostgreSQL 数据库自增序列问题记录

1.创建序列并绑定id CREATE SEQUENCE biz_factory_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;"id" int4 NOT NULL DEFAULT nextval(sys_user_seq::regclass), 2.实体设置KeySequence和TableId注解 注意IdType.INPUT 和 KeySequence(value …

Java巅峰之路---基础篇---综合练习(面向对象)

目录 文字版格斗游戏 基础版 souf输出语句 进阶版 键盘录入的说明 复杂对象数组练习 需求: 添加和遍历 删除和遍历 修改和遍历 文字版格斗游戏 基础版 格斗游戏,每个游戏角色的姓名,血量,都不相同,在选定人…

c++入门基础篇(上)

目录 前言: 1.c++的第一个程序 2.命名空间 2.1 namespace的定义 2.2 命名空间使用 3.c++输入&输出 4.缺省参数 5.函数重载 前言: 我们在之前学完了c语言的大部分语法知识,是不是意…

论文学习_An Empirical Study of Deep Learning Models for Vulnerability Detection

1. 引言 研究背景:近年来,深度学习漏洞检测工具取得了可喜的成果。最先进的模型报告了 0.9 的 F1 分数,并且优于静态分析器。结果令人兴奋,因为深度学习可能会给软件保障带来革命性的变化。因此,IBM、谷歌和亚马逊等行业公司非常感兴趣,并投入巨资开发此类工具和数据集。…