Google Guice 1:如何实现依赖注入?

news2024/11/19 20:44:09

1. 待完善的邮箱程序

1.1 手动注入依赖

  • 前一篇博文《谈谈自己对依赖注入的理解》,笔者只是基于依赖注入的思想,为EmailClient预留了依赖注入的入口

    到目前为止,我们只是让dependent class预留了依赖注入的入口,要想实现依赖的自动注入,还需要依赖注入框架的辅助

  • 如果不借助依赖注入框架,依赖的注入只能依靠程序员手动实现

    public class Main {
        public static void main(String[] args) {
            EmailService emailService = new GoogleEmailService();
            EmailClient emailClient = new EmailClient(emailService);
    
            // 发送邮件
            emailClient.sendEmail("12345@gmail.com", "Hello lucy !");
        }
    }
    

1.2 通过Google Guice注入依赖

  • 使用Google Guice,一个轻量级的Java依赖注入框架,可以实现依赖的自动注入

    Guice is a lightweight dependency injection (DI) framework for Java.

  • 声明依赖注入:需要为EmailClient的构造函数添加@Inject注解,表明这是一个需要依赖注入的构造函数

    public class EmailClient  {
        private EmailService service;
    
        @Inject
        public EmailClient(EmailService service) {
            this.service = service;
        }
        // 其他方法省略
    }
    
  • 定义依赖图:EmailService只是一个接口,EmailClient实际依赖EmailService的哪个具体实现,需要在Module中进行定义

    public class EmailModule extends AbstractModule {
    
        @Override
        protected void configure() {
            // QQEmailService绑定为EmailService的实现
            bind(EmailService.class).to(QQEmailService.class);
        }
    }
    
  • Module中的依赖关系,最终将形成整个应用程序的依赖图

  • 创建Injector,获取实例:基于自定义的Module创建Injector,Injector内部包含整个应用程序的依赖图。

  • 当我们从Injector请求一个实例时,Injector将找出要创建的对象,以及创建这个对象所需的依赖,然后返回一个**“完整”**的对象

    public class Main {
        public static void main(String[] args) {
            // 将Module传递给Injector,让其了解依赖图
            Injector injector = Guice.createInjector(new EmailModule());
            // 向Injector请求一个现成的EmailClient
            EmailClient emailClient = injector.getInstance(EmailClient.class);
            // 使用EmailClient
            emailClient.sendEmail("injector_guice@gmail.com", "Hello lucy !");
        }
    }
    
  • 执行结果如下,EmailClient使用的是EmailModule中绑定的QQEmailService

2. Guice的依赖注入方式

2.1 Constructor Injection

  • 上面代码示例,就是Constructor Injection,它实现了依赖注入和类实例化的整合,是Guice最推荐的一种依赖注入方式

    依赖注入和类实例化的整合

  • 使用@Inject标识构造函数,告诉Injector这既是是依赖注入的入口,还是创建实例对象的入口

  • 如果该类还存在其他构造函数,Injector只会调用@Inject标识的构造函数来创建实例对象

    public class EmailClient  {
        private final EmailService service;
    
        public EmailClient() {
            System.out.println("EmailClient: no-args constructor");
            this.service = new GoogleEmailService(); // 默认使用GoogleEmailService
        }
    
        @Inject
        public EmailClient(EmailService service) {
            System.out.printf("EmailClient: constructor with %s\n", service.getClass().getSimpleName());
            this.service = service;
        }
        // 省略其他代码
    }
    
  • 最终,执行结果如下

    Guice最推荐的一种依赖注入方式

  • 因为使用这种方式,方便进行单元测试,具体可以查看Guice官网:BINDING_ALREADY_SET

    @Test
    public void sendEmailTest() {
        // mock出EmailService并注入factory
        EmailService mockService = mock(EmailService.class);
        // 创建client,通过构造函数直接注入mock出来的EmailService
        EmailClient emailClient = new EmailClient(mockService);
        // 调用emailClient.sendEmail()方法,将调用mock的sendEmail()方法
        emailClient.sendEmail("sunrise@gmail.com", "Hello lucy!");
        verify(mockService).sendEmail("sunrise@gmail.com", "Hello lucy!");
    }
    

疑问:如果没有使用@Inject标识构造函数,能否成功注入依赖?

  • 如果没有使用@Inject标识构造函数,Guice将默认使用public类型的无参构造函数
  • 无参构造函数,自然不能通过构造函数的入参注入依赖
  • 例如,上面的代码去除@Inject注解,最终将使用第一个构造创建EmailClient对象。此时,EmailService不再是通过依赖注入的,而是EmailClient自己创建的
  • 如果某个类没有public类型的无参构造函数,则Guice无法为其创建实例对象,程序执行将报错

2.2 Method Injection

  • 还可以使用@Inject注解标记setter方法,实现依赖的自动注入。这样的依赖注入方式,叫做Method Injection

    public class EmailClient {
        private EmailService service;// 不能再使用final进行标识
    
        public EmailClient() {
            System.out.println("EmailClient: no-args constructor");
        }
    
        @Inject
        public void setService(EmailService emailService) {
            System.out.println("EmailClient: method injection");
            this.service = emailService;
        }
        // 其他代码省略
    }
    
  • 最终,执行结果如下,可知:Guice在调用无参构造函数创建完实例对象后,还通过setter方法自动注入了EmailService

  • Method Injection破坏了成员变量的稳定性,因为不能再使用final对其进行修饰。

  • 而大多数开源项目中,成员变量都是使用final进行修饰的以保证其不可变性。因此,它们基本都是选择Constructor Injection

2.3 Field Injection

  • 同时,如果使用Method Injection实现依赖注入,对于一个大量依赖其他类的dependent class来说,则需要定义大量的setter方法,这是十分不友好的

  • 这时,可以使用Field Injection:在定义成员变量时使用@Inject注解

    public class EmailClient {
        @Inject
        private EmailService service;// 不能再使用final进行标识
    
        public EmailClient() {
            System.out.println("EmailClient: no-args constructor");
        }
        // 其他代码省略
    }
    // 同时,在QQEmailService中增加如下构造函数
    public QQEmailService() {
        System.out.println("This is QQEmailService ...");
    }
    
  • 最终,从Guice得到的EmailClient成功注入了QQEmailService依赖

  • 同样的,Field Injection也破坏了成员变量的不可变性

2.4 其他的依赖注入方式

  • Guice官方文档Injections部分,还介绍了很多其他的依赖注入方式,可以自行学习
  • 从笔者对开源代码的有限阅读来看,基本都是使用Constructor Injection实现依赖注入

3. 总结

  • 笔者喜欢按照自己的思维习惯进行学习总结,因此会与Guice官方文档的组织顺序不一致
  • 将依赖注入作为第一篇学习总结,是因为后面很多的知识都将涉及依赖注入

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TOPLAS‘07: Effective Field-Sensitive Pointer Analysis for C 字段敏感C程序指针分析

文章目录1. 集合约束式的指针分析1.1 基本介绍1.2 求解约束1.2.1 图传播1.2.2 迭代顺序1.2.3 节点替换 (Variable Subsititution)1.2.4 传递化简 (Transitive Reduction)1.2.5 集合的表示1.2.6 差分传播1.2.7 相同解的集合2. 扩展约束模型2.1 简介2.2 处理函数指针2.3 处理字段…

NNOM第一个模型实例

目录 一、keras开发环境搭建 二、安装visual studio 2019 1. 下载安装 2. 配置使用MSVC编译器 三、编译第一个NNOM的demo 1. 下载源码 2. 安装依赖库 3. 编译auto_test 四、移植 1. 新建新的VS项目 2. 拷贝相关源码 3. 配置工程 4. 编译并运行 一、keras开发环境搭…

Java并发——线程池

线程池 一、线程池的作用 线程的创建和销毁需要占用CPU资源,若频繁的进行创建和销毁会产生很大的开销,影响性能和系统稳定性。 线程池的优点: 线程池可以保存创建好的线程随用随取,降低资源消耗(重复利用线程池中的…

一文读懂堡垒机对企业信息安全起到的重要作用

堡垒机的发展历程大致可分为以下三个阶段:      第一代堡垒机:堡垒机最初的理念起源于跳板机,但跳板机无法实现对运维人员操作行为进行控制和审计,一旦出现违规操作导致操作事故,很难快速定位原因和责任人。    …

Java分析-对象头

前言 HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding) HotSpot虚拟机的对象头(Object Header)包括两部分信息,第一部分用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁…

移动是否是商业bi的前景?

一 前言 五年前就有人预言商业智能BI移动化会成为必然趋势,如今5年时间已过,移动BI的普及程度并不如预期。原因主要是数据分析的交互性一直是很高的要求,手机屏幕的限制一直抑制了商业智能BI在移动端得到更好发挥的障碍。 比如数据看板或可…

[笔记] - springboot-jpa 使用sqlite 踩坑

前言(可略过) 最近准备写一些小项目来验证一下脑袋中的项目 因为是“小项目”,所以对于数据持久化的实现,就不想用mysql等很重的db了 而且不用考虑安全性,故首先想到的就是使用 sqlite 本地数据库即可 然后因为是使用…

Android进阶 之 SPI机制及实现原理

什么是SPI SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用…

BCryptPasswordEncoder加密与MD5加密的区别

MD5 加密说明 MD5(Message Digest Algorithm 5)中文名为消息摘要算法第五版,是计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。 MD5作为一种常用的摘要算法(或指纹算法),其…

一文教会你如何利用领英多账号高效开发客户资源

作为全球最大的职业社交平台,领英(linkedin)的属性关键词包括“商业、互动和机会”。这些属性覆盖了领英全球超过6亿的用户,这决定了领英是一个拥有无限商业交易机会的社交平台。因此,越来越多的国内外企业不断在领英上…

如何在右键菜单添加将文档“转换为PDF”选项

本文介绍一种方法,可以实现右键快速将docx、doc、txt、ppt等文档转换为PDF文档 文章目录1. Acrobat DC 软件安装2.添加右键“转PDF”功能选项3.功能效果1. Acrobat DC 软件安装 下载链接: 1.百度网盘:链接 提取码: vumk 2.阿里云盘:链接…

虹科分享|关于SANS报告的顶级勒索软件洞察

近年来,勒索软件攻击经历了大流行加速的演变,而防御系统则难以跟上。勒索软件的第一阶段已经让位于新的、不同的、更好的和更坏的东西。为了帮助理解这一演变,Morphisec赞助了一份来自SANS的报告,探索勒索软件防御的现状。它研究了…

从Pearson相关系数到模板匹配的NCC方法

文章目录<center> NCC(Normalized Cross Correlation)1.**Pearson相关系数**2.**协方差 covariance**3. **方差 variance**4.模板匹配中的NCC方法5.实现过程6.测试结果7.部分核心源码NCC.cppNCC(Normalized Cross Correlation)从Pearson相关系数到模板匹配的NCC方法 1.P…

HTML5 本地存储

文章目录HTML5 本地存储Cookie的缺点localStorage简介简单使用sessionStorage简介简单使用indexedDB简介HTML5 本地存储 Cookie的缺点 在HTML4.01中&#xff0c;想要在浏览器端存储用户的某些数据时&#xff0c;我们一般只能使用Cookie来实现。 但是Cookie存在一些问题&…

如何进行企业设备管理?

如何进行企业设备管理&#xff1f; 点进这篇文章&#xff0c;让企业设备管理不再 难 难 难 &#xff01; 对于许多公司来说&#xff0c;特别是制造业&#xff0c;生产设备已成为企业生产线中最重要最核心的部分&#xff0c;因此设备管理是企业管理基础的重要组成部分。而在当…

mysql-基础-约束多表关系多表查询事务

文章目录mysql基础1&#xff0c;约束1.1 概念1.2 分类1.3 非空约束1.4 唯一约束1.5 主键约束1.6 默认约束1.7 约束练习1.8 外键约束1.8.1 概述1.8.2 语法1.8.3 练习2&#xff0c;数据库设计2.1 数据库设计简介2.2 表关系(一对多)2.3 表关系(多对多)2.4 表关系(一对一)2.5 数据库…

刘鹏的2022年度总结

[ 这是 2022 博客之星 的竞选帖子&#xff0c; 请你在这里增加其他内容。接下来分享这一年的收获&#xff0c;感悟&#xff0c;以及 对CSDN 产品的反馈和 2023 年的希望。 ] 目录 1. 学习收获 1.1 心路历程 1.2 基本收支 2. 未来展望 2.1 UR3机械臂ROS 2.2 论文 2.3 开…

电线电缆行业mes解决方案,打造全新信息化车间

电线电缆行业虽然只是一个配套行业&#xff0c;却占据着中国电工行业1/4的产值。它产品种类众多&#xff0c;应用范围十分广泛&#xff0c;涉及到电力、建筑、通信&#xff0c;制造等行业&#xff0c;与国民经济的各个部门都密切相关。电线电续还被称为国民经济的“动脉”与“神…

STM32理论 —— 看门狗

文章目录1. 简述2. 独立看门狗 IWDG2.1 IWDG 相关寄存器2.1.1 键值寄存器IWDG_KR2.1.2 预分频寄存器IWDG_PR与重装载寄存器IWDG_RLR2.2 核心代码1. 简述 STM32 内部自带了 2 个看门狗&#xff1a;独立看门狗&#xff08;IWDG&#xff09;和窗口看门狗&#xff08;WWDG&#xff…

5. 最长回文子串

题目描述 给你一个字符串 s&#xff0c;找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同&#xff0c;则该字符串称为回文字符串。 示例 1&#xff1a; 输入&#xff1a;s “babad” 输出&#xff1a;“bab” 解释&#xff1a;“aba” 同样是符合题意的答案。 示…