Google Guice超轻量级依赖注入容器

Google Guice是Goolge开源的一款超轻量级依赖注入容器,超轻量的特点主要体现在:可与其它依赖注入容器混合使用,例如和Spring/Spring Boot的IOC容器混合使用;不需要任何配置信息,只需要引入几个有限的依赖包即可以使用;使用简单,只需要掌握几个有限的注释就可以使用;相对更重的依赖注入容器,Google Guice运行速度更快,消耗更少的系统资源。
在这里插入图片描述
(图片来源于网络)

实际上大多数技术人员都在不知不觉地使用Google Guice,这是因为很多工具性的组件和中间件内部都通过Google Guice进行实例管理,诸如:Elasticsearch、Netty等。本文试图通过示例和知识点讲解结合的方式,向读者介绍Google Guice的最基本使用。

1、典型使用

我们先来看一个最简单的示例,这个实例包括了相当一部分在后文将要介绍的Google Guice知识点:

// 首先我们按照正常的编码流程,定义一个普通的接口和普通的实现类
public interface OrderService {public void doSomething();
}// ============================
// 以下是OrderService的一个普通实现
public class OrderServiceImpl implements OrderService {@Overridepublic void doSomething() {System.out.println(" ===== doSomething ===== ");}
}// ============================
// 然后我们将OrderService接口和OrderServiceImpl实现类的绑定关系,注册到依赖注入容器中
// 这个过程是通过一个Module的概念进行设计的
public class PlayerModule implements Module {@Overridepublic void configure(Binder binder) {// .....binder.bind(OrderService.class).to(OrderServiceImpl.class);// .....}
}// ============================
// 最后就可以通过依赖注入管理器,来进行使用了
// 只是一个Google Guice最简单的使用
public static void main(String[] args) {// 加载各个配置模块,module是Google Guice的一个概念,里面实际上是容器的实例映射信息Injector injector = Guice.createInjector(new Module[] {new PlayerModule()});// 从依赖容器中取得实例OrderService orderService = injector.getInstance(OrderServiceImpl.class);// 开始调用具体的工作方法orderService.doSomething();
}
// ......
  • Injector:是Google Guice中的一个概念,是依赖注入容器(管理器),一个应用程序中可以根据实际情况创建一个或者多个依赖注入容器(管理器)。

  • Module:是Google Guice中的另一个概念,可以看作模块配置信息。其中设定了依赖注入容器中实例对象和接口、实例对象和创建器等在依赖注入容器中的绑定关系。以上代码中,我们基于一个Module创建了一个依赖注入容器(管理器)。

  • 除了Google Guice专有的几个概念外,对于OrderService接口和它的实现 OrderServiceImpl上,并不需要增加特别的方法、属性或者注解。

2、Google Guice中的单例

和大家经常使用的Spring IOC容器相比,Guice依赖注入容器最需要注意的是,容器中的实例默认情况下并不是单例模式,而是多例模式。如果要求注入容器中的实例是单例模式,就需要在对应的Module中进行设定,或者通过@Singleton注解进行设定。 以下代码是在Module中绑定注册时进行单例模式的设定:

public class XXXXX implements Module {@Overridepublic void configure(Binder binder) {// ......// asEagerSingleton()方法,就是设置成单例模式binder.bind(Service.class).annotatedWith(Names.named("one")).to(OneService.class).asEagerSingleton();// ......}
}

以下是通过注解方式进行单例模式的设定,注意@Singleton注解一定要加在直接注册到Module中的具体类上,如果@Singleton注解写在OrderServiceImpl类上,但是在Module设定时却描述为一个Provider(后文会讲),那么@Singleton注解将不再起作用:

// 使用@Singleton注解,表示单例
@Singleton
public class OneService implements Service {//  类中的各种内容可以忽略
}

3、Google Guice中的创建器

在很多情况下,技术人员需要在依赖注入容器创建一个实例时,加入一些特定的逻辑。也就是说需要干预依赖注入容器创建实例的过程。这时技术人员就需要通过设定一个Provider来完成特定实例在创建时的干预过程,如下所示:

// 注意,如果使用Provider,那么加载在World上面的Singleton注释会失效
public class WorldProvider implements Provider<World> {@Overridepublic World get() {// 这是创建World类实例对象的过程// 具体代码忽略World world = new World();// ......return world;}
}

以上Provider的代码很好理解,就是描述一个具体的对象实例应该怎么进行创建。在设定完成后,Module中的相关设定方式也要进行调整,如下所示:

public class XXXXX implements Module {@Overridepublic void configure(Binder binder) {// ......// 将这个Provider注册到容器binder.bind(World.class).toProvider(new WorldProvider())// ......}
}

4、Google Guice中的默认实现和多个实现

有的情况下,应用程序中一个接口可能有多个实现,并且这些实现都需要注入到容器中进行管理。那么这些实现就需要指定一个默认实现,这样才能保证注入管理器(Injector)能够正常工作。Google Guice主要提供了两种注解方式来为接口指定默认的实现方式。分别是@ImplementedBy注解和@ProvidedBy注解,示例代码如下:

// 使用@ImplementedBy注解,说明这个接口的默认实现是OneService
@ImplementedBy(OneService.class)
public interface Service {public void doSomething();public void doOther();
}// 或者,使用@Provided注解,说明这个接口默认的创建器是WorldProvider
@ProvidedBy(WorldProvider.class)
public interface OrderService {public void doSomething();
}

@ImplementedBy注解加载到Service接口上,说明这个接口的默认实现为OneService类;@ProvidedBy注解加载到Service接口上,说明这个接口的默认实例创建的工作,由WorldProvider负责完成。当一个接口拥有多个实现时,除了为这个接口指定默认实现外,还需要为注入容器的多个实现分别指定辨识名。这个辨识名可以使用Google Guice提供的@Names注解,也可以使用Google Guice提供的注解扩展@BindingAnnotation。以下是给出的示例:

public class XXXXX implements Module {@Overridepublic void configure(Binder binder) {// ......// 通过一个别名绑定接口和它的实现// 分别给Service接口的两个实现,设定了别名“one”和“two”// 别名设置为“one”的具体实现OneService,还设定了以单例模式工作binder.bind(Service.class).annotatedWith(Names.named("one")).to(OneService.class).asEagerSingleton();binder.bind(Service.class).annotatedWith(Names.named("two")).to(TwoService.class);// ......}
}// ========= 那么从依赖注入容器中获取对象实例使用时,可以这样来编码
// 这只是一种获取方式,后文还会介绍另外一种
@Named("one")
Service service = injector.getInstance(Service.class);

以上代码为@Named注解的使用,包括Module中设定一个接口的多个实现时,如何为每个实现设置不同的名字,以及在获取实例时如何使用@Names注解获取特定的实现。还有一种方式是使用@BindingAnnotation注解创建多个新的注解,来标识不同的实现。具体示例如下:

// =========== 
// 首先我们定义两个注解One和Two
// 主要关注@BindingAnnotation注解,这个注解表明,One注解可以用来标识和区分具体的实现类
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.LOCAL_VARIABLE)
public @interface One {}// 主要关注@BindingAnnotation注解,这个注解表明,Two注解可以用来标识和区分具体的实现类
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.LOCAL_VARIABLE)
public @interface Two {}// =========== 
// 接着我们可以使用这两个注解,区分一个接口的两个不同实现
public class XXXXX implements Module {@Overridepublic void configure(Binder binder) {// ......// 通过两个注解区分Service接口的两个不同实现binder.bind(Service.class).annotatedWith(One.class).to(OneService.class);binder.bind(Service.class).annotatedWith(Two.class).to(TwoService.class);// ......}
}// ===========
// 最后,从依赖注入容器中获取对象实例使用时,可以这样来编码
// 这只是一种获取方式,后文还会介绍另外一种
@One
Service service = injector.getInstance(Service.class);

以上代码通过@BindingAnnotation创建了两个新的注解,分别是@One和@Two,然后在Module注册该接口的不同实现时,为不同实现分别绑定不同的注解。最后在获取实例时,使用已经绑定的不同注解,就可以获取对应的实例了。Google Guice的依赖注入容器(管理器)也提供了方法,可以让开发者中取得已注册到容器中的,某一个接口的所有实现。示例如下:

// ......
List<Binding<Service>> serviceBindings = injector.findBindingsByType(TypeLiteral.get(Service.class));
// 通过findBindingsByType方法,开发人员可以获取Service接口中的一个或者多个实现
// ......

5、Google Guice 中的Module

在以上各小节中,为了向读者介绍相关知识点,实际上本文已经或多或少涉及了Google Guice中的Module使用方式。本节我们主要进行Module设定方式的总结。

5.1、绑定接口和类

Google Guice可以注册到依赖注入容器的类型可以很多,除了我们一般知道的接口以外,普通的类也可以注入到容器中。代码片如下所示:

public class XXXXX implements Module {@Overridepublic void configure(Binder binder) {// ......// 注册普通的类到容器binder.bind(World.class);// ......}
}

除此以外,Google Guice可以使用以下很多种方式绑定接口和它的实现:

public class XXXXX implements Module {@Overridepublic void configure(Binder binder) {// ......// 通过一个别名绑定接口和它的实现binder.bind(Service.class).annotatedWith(Names.named("one")).to(OneService.class);// 通过自定义注解绑定接口和它的实现binder.bind(Service.class).annotatedWith(One.class).to(OneService.class);// 直接绑定一个接口和它的实现binder.bind(Service.class).to(OneService.class);// ......}
}

5.2、绑定实例

除了绑定类以外,Google Guice还可以将一个已经完成实例化的对象,或者一个实例化过程注册到容器中,代码实例如下:

public class XXXXX implements Module {@Overridepublic void configure(Binder binder) {// ......// 可以直接注入一个实例对象到容器中OrderService orderService = new OrderServiceImpl();binder.bind(OrderService.class).toInstance(orderService);// 也可以是一个实例化过程binder.bind(OrderService.class).toInstance(new OrderService() {@Overridepublic void doSomething() {// 这个实例创建的创建过程// ........}});// ......}
}

通过这种注册方式,开发人员也是可以干预某个实例对象的创建过程的。但就本文来说,还是推荐使用创建器的方式进行实例对象创建过程的干预。

5.3、绑定创建器

可以使用一下方式向依赖注入容器注册一个创建器,以便在某个特定实例对象创建时干预对象的创建过程:

public class XXXXX implements Module {@Overridepublic void configure(Binder binder) {// ......// 注意,这里还设定了实例对象以单例模式工作binder.bind(World.class).toProvider(new WorldProvider()).asEagerSingleton();// ......}
}

另外,Google Guice还提供了@Provides注解,来设定一个实例对象的创建方法。@Provides注解是放置在方法上的一个注解,并且这个方法必须属于某一个Module。示例代码如下所示:

public class XXXXX implements Module {@Overridepublic void configure(Binder binder) {// 这个方法可以进行其他类型的绑定}// ......// 这个方法必须放置在某个Module中// 直接设定了如果创建OrderService接口的实例@Providespublic OrderService one() {return new OrderServiceImpl();}
}

5.4、甚至可以绑定常量

一个固定的字符串当然可以进行注入:

public class XXXXX implements Module {@Overridepublic void configure(Binder binder) {// ......binder.bind(String.class).toInstance("这是一个固定的字符串");// ......}
}

5.5、通过@Inject注解使用已注入的实例

以上本文介绍的内容,都是向依赖注入容器进行各种形式注册的示例,那么怎么进行容器中对象实例的使用呢?Google Guice提供了两种使用容器中实例对象的方式,一种是上文出现过的依赖注入管理器(Injector);另一个是使用@Inject注解。代码实例如下:

// ......
// 加载各个配置模块,module是Google Guice的一个概念,里面实际上是容器的实例映射信息
// 得到一个依赖注入容器的管理器
Injector injector = Guice.createInjector(new Module[] {new PlayerModule()});
// 然后从依赖诸如容器中取得实例
OrderService orderService = injector.getInstance(OrderServiceImpl.class);
// ......

以上这种使用依赖注入管理器的方式并不适合大多数编码场景,因为不可能在所有场景下都先获取一个依赖注入管理器,再获取实例对象。更多的场景中,我们使用的是@Inject注解。@Inject注解可以设定在某个属性上,也可以设定在某个构造函数上。如下所示:

public class XXXXXX {// 加载在属性上@Injectprivate OrderService orderService;// 如果一个接口有多个实现类,并使用自定义注解进行标识,则这里可以这样使用@Oneprivate Service service;// 如果一个接口有多个实现类,并使用别名进行标识,则这里可以这样使用@Named("one")private Service service;// @Inject还可以加载在构造函数上,这时Google Guice会自动进行入参的匹配(如果有入参的话)// 当然,如果无法明确参数中具体的实现,还可以使用自定义注解或者别名注解进行说明@Injectpublic XXXXXX(String value , Service service);// ......
}

之所以介绍Google Guice,是因为在一篇专栏中其中的一块实战示例会使用这个轻量级依赖注入框架。当然Google Guice也可以应用在很多组件或者小型应用工程中。

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

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

相关文章

无线和移动网络

背景 两个重要的挑战 无线&#xff1a;通过无线链路通信移动&#xff1a;需要网络处理移动&#xff08;不同变换所接入的网络&#xff09;用户 无线网络中的组件 无线主机&#xff08;无线并不总是意味着移动的&#xff09;基站&#xff08;base station 或者叫AP&#xff0…

知乎知+广告推广开户充值的返点政策是怎样?

如何让您的品牌精准触达目标受众&#xff0c;实现高效传播与转化&#xff0c;成为了每一位市场人面临的挑战。为此&#xff0c;云衔科技作为业界领先的数字营销解决方案提供商&#xff0c;正式宣布全面支持知乎知广告开户及一站式代运营服务&#xff0c;旨在帮助各行业客户在知…

网鼎杯 2020 玄武组 SSRFMe

复习一下常见的redis主从复制 主要是redis伪服务器的选择和一些小坑点 <?php function check_inner_ip($url) { $match_resultpreg_match(/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/,$url); if (!$match_result) { die(url fomat error); } try { …

【iOS】——Runtime学习

文章目录 一、Runtime介绍二、Runtime消息传递三、实例对象、类对象、元类对象四、isa_t结构体的具体实现五、cache_t的具体实现六、class_data_bits_t的具体实现七、Runtime消息转发动态方法解析备用接收者完整消息转发 一、Runtime介绍 iOS的Runtime&#xff0c;通常称为Obj…

带你了解消防安全与应急救援,2024北京消防展6月盛大开启

带你了解消防安全与应急救援&#xff0c;2024北京国际消防展6.26盛大开启 在日益关注安全问题的今天&#xff0c;消防安全与应急救援已经成为社会发展的重要一环。为了提高全民消防安全意识&#xff0c;推动应急救援技术的发展&#xff0c;2024年北京国际消防展将于6月26日盛大…

纷享销客安全体系:物理与环境安全

纷享销客的物理设备托管在经过严格准入制度授权的TIER3级别以上的专业数据中心&#xff0c;这些数据中心均通过了等保三级与IS027001安全认证&#xff0c;确保电力、制冷等基础设施提供相应级别的冗余&#xff0c;以增强IDC环境的安全性。 业务操作系统平台采用当前广泛使用的…

点云获取pcl点云以某个点云的已经分块得区域的交集

首先将点云分块得到区域后&#xff0c;获取每个块的box的最大最小点云&#xff0c;然后提取box内的点云。 pcl::IndicesPtr indexes(new pcl::Indices());pcl::getPointsInBox(*cloud_1, min_pt, max_pt, *indexes);// --------------------------取框内和框外点--------------…

手持终端RFID电子标签读写器超高频手持机

RFID手持机具备RFID读写功能&#xff0c;可以对RFID标签进行识读&#xff0c;是有特定功能的PDA(便携式移动终端)。 作为现代化信息管理工具的重要组成部分&#xff0c;其强大的功能和便捷的操作性正在越来越多的领域得到应用。从物流仓储到零售管理&#xff0c;从生产制造到医…

OZON海关税费是多少,OZON要交关税吗

在跨境电商领域&#xff0c;OZON作为俄罗斯知名的电商平台&#xff0c;吸引了众多国内外商家的目光。然而&#xff0c;当商家考虑在OZON平台上开展业务时&#xff0c;一个不可回避的问题就是海关税费和关税问题。本文将详细探讨OZON海关税费的相关内容&#xff0c;帮助商家更好…

使用C++实现YOLO图像分类:从环境搭建到性能评估的完整指南

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三连支…

面试题------>JVM虚拟机!!!

一、Java对象内存布局 二、JVM 内存结构 程序计数器: 线程私有的(每个线程都有一个自己的程序计数器),是一个指针.代码运行,执行命令.而每个命令都是有行号的,会使用程序计数器来记录命令执行到多少行了.记录代码执行的位置. Java虚拟机栈: 线程私有的(每个线程都有一个自己…

Vitis HLS 学习笔记--接口聚合与解聚-AXI主接口

目录 1. 简介 2. 用法及语法 3. 详细解读 4. 总结 1. 简介 在使用 Vitis HLS 工具进行硬件设计时&#xff0c;如果你在接口上使用了结构体&#xff0c;工具会自动把结构体里的所有元素组合成一个整体。就像把一堆零件组装成一个玩具一样。这样做的好处是&#xff0c;数据可…

mysql中 redo日志(上)

大家好。我们知道InnoDB 存储引擎是以页为单位来管理存储空间的&#xff0c;我们进行的增删改查操作其实本质上都是在访问页面。而在真正访问页面之前&#xff0c;需要把在磁盘上的页缓存到内存中的Buffer Pool之后才可以访问。那么我们思考一个问题&#xff1a;如果我们只在内…

沃通CA参与《证书透明规范》及《自动化证书管理规范》两项商密标准制定

沃通CA加入由零信技术牵头的两项商密标准《证书透明规范》及《自动化证书管理规范》编制工作。沃通CA作为国内依法设立的电子认证服务机构与领先的SSL证书服务商&#xff0c;很荣幸参与到两项商密标准的编制工作中&#xff0c;不仅提供多年SSL证书领域的应用经验&#xff0c;还…

AUTOSAR网络管理报文(学习笔记)

文章分为三个部分来 简绍AUTOSAR的网络管理的优点或缺点 AUTOSAR全称AUTomotive Open System ARchitecture&#xff08;汽车开放系统架构&#xff09;。有一点需要注意 注意看全称中的英文大写部分&#xff0c;写全称时必须要按照上面的格式写&#xff0c;不能只写首字母大写…

--- JAVA 多态 ---

多态&#xff0c;顾名思义就时有多种形态&#xff0c;那咋样才嫩共有多种形态呢&#xff0c;再java中就是用不同的对象去调用同一个方法&#xff0c;产生了不同的结果。 看这段代码&#xff0c;我调用的是同一个方法&#xff0c;且只是传入的对象的不同&#xff0c;但是产生了不…

Linux网络服务之SSH(远程访问及控制)

ssh远程管理&#xff1a; ssh是一种安全通道协议&#xff0c;用来实现字符界面的远程登录。远程复制&#xff0c;远程文本传输。 ssh对通信双方的数据进行了加密 用户名和密码登录 密钥对认证方式&#xff08;可以实现免密登录&#xff09; ssh 22 网络层 传输层 数据传输…

【成品设计】基于红外线的目标跟踪无线测温系统设计

《基于红外线的目标跟踪无线测温系统设计》 整体功能&#xff1a; A端&#xff1a;无线跟踪端 主控&#xff1a;采用STM32F103C8T6单片机作为核心控制。360度编码模块数字脉冲输出红外解码编码模块OLED屏幕。 B端&#xff1a;无线待测端 主控&#xff1a;采用STM32F103C8T…

C语言杂谈:函数栈帧,函数调用时到底发生了什么

我们都知道在调用函数时&#xff0c;要为函数在栈上开辟空间&#xff0c;函数后续内容都会在栈帧空间中保存&#xff0c;如非静态局部变量&#xff0c;返回值等。这段空间就叫栈帧。 当函数调用&#xff0c;就会开辟栈帧空间&#xff0c;函数返回时&#xff0c;栈帧空间就会被释…

SpringBoot——整合Servlet的三大组件:过滤器(Filter)

目录 过滤器 一、用过滤器检查用户是否登录 LoginFilter自定义过滤器 FilterConfig配置类 FilterController控制器 SpringbootFilterApplication启动类 二、用过滤器统计资源访问量 LoginFilter FilterController 在开发SpringBoot项目时&#xff0c;开发人员经常需…