• Google开源依赖注入框架-Guice指南


    持续坚持原创输出,点击蓝字关注我吧

    作者:软件质量保障
    知乎:https://www.zhihu.com/people/iloverain1024

    之前发过一篇文章《浅谈依赖注入的实现》,介绍了依赖注入的实现原理。文中提到高效实现依赖注入的工具Guice,本文就介绍一下这款Google开源的依赖注入框架Guice及其使用方法。

    1. 简介

    Google Guice 是一个轻量级的依赖注入框架,它支持Java 5或者更高版本的JDK,得利于Java 5中提供的泛型 (Generics) 和注解 (Annotations) ,它可以使得代码类型安全 (type-safe) 。那么何时使用在代码中使用 Guice 进行注入呢?一般来说,如果在你的应用代码中业务对象 (Business Objects) 之间的关系或者依赖需要维护的话,你就可以使用Guice 进行注入。

    本文会通过一些例子来初步的认识一下 Guice 框架。

    当然,不了解依赖注入基础知识的同学建议先看下这篇科普贴 《浅谈依赖注入的实现》。

    2. 添加依赖

    将以下依赖项添加到Maven项目中放入pom.xml中:

    <dependency><groupId>com.google.inject</groupId><artifactId>guice</artifactId><version>4.1.0</version></dependency>

    3. Guice的基础用法

    3.1 项目样例代码

    我还是用上篇文章中那个例子作为演示场景,即以现实生活中的三种通信方式为例:Email、SMS 和 IM。

    首先,我们定义Communication类:

    public class Communication {    @Inject     private Logger logger;    @Inject    private Communicator communicator;    public Communication(Boolean keepRecords) {        if (keepRecords) {            System.out.println("Message logging enabled");        }    }    public boolean sendMessage(String message) {        return communicator.sendMessage(message);    }}

    这个Communication类是通信基类,此类的实例实现了通过可用的通信通道发送消息。如上代码所示,Communication会依赖Communicator,我们通过调用它来进行实际的消息传输。

    Guice最基础的用法就是通过Injector对象实现,下面是客户端代码的例子:

    public static void main(String[] args){    Injector injector = Guice.createInjector();    Communication comms = injector.getInstance(Communication.class)    comms.sendMessage("软件质量保障");    }

    Guice 对依赖注入和管理采用代码优先的策略,因此我们可以不用处理很多令人抓狂的XML配置。

    3.2. Guice bind

    Binding is to Guice as wiring is to Spring。通过bind,我们可以实现Guice如何将依赖项注入到一个类中,

    我们在com.google.inject.AbstractModule的实现中定义:

    public class BasicModule extends AbstractModule {    @Override    protected void configure() {        bind(Communicator.class).to(DefaultCommunicatorImpl.class);    }}

    此模块实现将Communicator绑定到其默认实现类DefaultCommunicatorImpl上,在找到Communicator的地方都将注入Default CommunicatorImpl的实例。

    3.3. @Named注解

    我们可以使用 @Named注解来命名这些实体类,当你给它一个命名,它会返回一个命名好的 Annotation。例如在上面的例子中,可以使用 Names.named() 来完成相同的事情。

    @Inject @Named("DefaultCommunicator")Communicator communicator;

    @Overrideprotected void configure() {    bind(Communicator.class)      .annotatedWith(Names.named("DefaultCommunicator"))      .to(DefaultCommunicatorImpl.class);}

    使用@Named(“DefaultCommunicator”)注解将Communicator绑定到DefaultCommunicator实现类。

    3.4. 构造函数绑定

    我们还可以使用构造函数绑定注入一个没有默认无参数构造函数的依赖对象:

    public class BasicModule extends AbstractModule {    @Override    protected void configure() {        bind(Boolean.class).toInstance(true);        bind(Communication.class).toConstructor(          Communication.class.getConstructor(Boolean.TYPE));}

    构造函数绑定的另一种方法是实例绑定,我们直接为Communication.class绑定一个实例:

    public class BasicModule extends AbstractModule {    @Override    protected void configure() {        bind(Communication.class)          .toInstance(new Communication(true));    }    }

    无论我们在何处声明Communication类,此绑定都将提供Communication类的实例。但是在这种情况下,类的依赖关系树不会自动关联。

    4. 依赖注入类型

    Guice支持DI所推荐的标准注入类型。假设在Communicator类中,我们需要注入不同类型的CommunicationMode,可以通过下面几种方法实现。

    4.1 属性注入

    @Inject @Named("SMSComms")CommunicationMode smsComms;

    我们可以使用@Named注解作为限定符来实现基于名称的定向注入。

    4.2. Method注入

    这里我们将使用一个setter方法来实现注入:

    @Injectpublic void setEmailCommunicator(@Named("EmailComms") CommunicationMode emailComms) {    this.emailComms = emailComms;}

    4.3. 构造函数注入

    我们还可以使用构造函数注入依赖:

    @Injectpublic Communication(@Named("IMComms") CommunicationMode imComms) {    this.imComms= imComms;}

    4.4. 隐式注入

    Guice 还提供隐式注入一些通用组件,例如Injector和java.util.Logger的实例等。大家是不是发现了,我们的所有示例都使用了Logger,但你是不是找不到它的实际绑定代码。

    5. Guice Scope机制

    Guice支持我们在其他DI框架中逐渐习惯的Scope和Scope机制。

    5.1 单例

    下面在我们的应用程序中注入一个单例,我们指定了Communicator的Scope,它将会被标志为一个单例实例。

    bind(Communicator.class).annotatedWith(Names.named("AnotherCommunicator"))  .to(Communicator.class).in(Scopes.SINGLETON);

    5.2. 饿汉式单例

    下面注入一个饿汉式单例,asEagerSingleton()方法用来标记单例模式。

    bind(Communicator.class).annotatedWith(Names.named("AnotherCommunicator"))  .to(Communicator.class)  .asEagerSingleton();

    喜欢的话,就点个赞和在看再走吧  👍👍👍👍👍👍

    - END -


    下方扫码关注 软件质量保障,与质量君一起学习成长、共同进步,做一个职场最贵Tester!

    • 后台回复【测开】获取测试开发xmind脑图

    • 后台回复【加群】获取加入测试社群!

    往期推荐

    聊聊工作中的自我管理和向上管

    经验分享|测试工程师转型测试开发历程

    聊聊UI自动化的PageObject设计模式

    细读《阿里测试之道》

    我在阿里做测开

  • 相关阅读:
    k8s入门:Helm 构建 MySQL
    9. 一个SpringBoot项目运行
    模拟经营微信小游戏-休闲餐厅上线了
    SQL查询:求每个组最大值,原来是这样写的(SQL分组求最值有哪些坑)
    基于Java Web的随意购商城系统
    漫谈:C、C++字符串的困局
    Thymeleaf th:insert、th:replace、th:include的使用
    【RabbitMQ】初识 RabbitMQ
    《QT从基础到进阶·二十六》绘制多个图形项(QGraphicsRectItem,QGraphicsLineItem,QGraphicsPolygonItem)
    抽象类和(上)
  • 原文地址:https://blog.csdn.net/csd11311/article/details/125466478