Google Guice 快速指南



Google Guice - 概述

Guice 是一个开源的、基于 Java 的依赖注入框架。它非常轻量级,并且由 Google 积极开发/维护。

依赖注入

每个基于 Java 的应用程序都有一些对象协同工作,以向最终用户呈现一个可运行的应用程序。在编写复杂的 Java 应用程序时,应用程序类应该尽可能独立于其他 Java 类,以增加重用这些类的可能性,并在单元测试期间独立于其他类对其进行测试。依赖注入(有时称为连接)有助于将这些类粘合在一起,同时保持它们的独立性。

假设您有一个应用程序,其中包含一个文本编辑器组件,并且您希望提供拼写检查功能。您的标准代码如下所示:

public class TextEditor {
   private SpellChecker spellChecker;
   
   public TextEditor() {
      spellChecker = new SpellChecker();
   }
}

我们在这里所做的是,在 TextEditor 和 SpellChecker 之间创建了一个依赖关系。在控制反转场景中,我们将改为执行以下操作:

public class TextEditor {
   private SpellChecker spellChecker;
   
   @Inject
   public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }
}

在这里,TextEditor 不应该担心 SpellChecker 的实现。SpellChecker 将独立实现,并在 TextEditor 实例化时提供给 TextEditor。

使用 Guice 进行依赖注入(绑定)

依赖注入由 Guice 绑定控制。Guice 使用绑定将对象类型映射到它们的实际实现。这些绑定在模块中定义。模块是绑定集合,如下所示

public class TextEditorModule extends AbstractModule {
   @Override 
   protected void configure() {
      /*
      * Bind SpellChecker binding to WinWordSpellChecker implementation 
      * whenever spellChecker dependency is used.
      */
      bind(SpellChecker.class).to(WinWordSpellChecker.class);
   }
}

模块是 Injector 的核心构建块,Injector 是 Guice 的对象图构建器。第一步是创建一个 Injector,然后我们可以使用 Injector 获取对象。

public static void main(String[] args) {
   /*
   * Guice.createInjector() takes Modules, and returns a new Injector
   * instance. This method is to be called once during application startup.
   */
   Injector injector = Guice.createInjector(new TextEditorModule());
   /*
   * Build object using injector
   */
   TextEditor textEditor = injector.getInstance(TextEditor.class);   
}

在上面的示例中,TextEditor 类的对象图由 Guice 构造,并且此图包含 TextEditor 对象及其依赖项作为 WinWordSpellChecker 对象。

Google Guice - 环境搭建

本地环境搭建

如果您仍然希望为 Java 编程语言设置环境,那么本节将指导您如何在机器上下载和设置 Java。请按照下面提到的步骤设置环境。

Java SE 可从以下链接免费获取 下载 Java。因此,您可以根据您的操作系统下载一个版本。

按照说明下载 Java 并运行.exe文件以在您的机器上安装 Java。在您的机器上安装 Java 后,您需要设置环境变量以指向正确的安装目录:

为 Windows 2000/XP 设置路径

我们假设您已将 Java 安装在c:\Program Files\java\jdk目录中:

  • 右键单击“我的电脑”,然后选择“属性”。

  • 在“高级”选项卡下单击“环境变量”按钮。

  • 现在,修改“Path”变量,使其还包含 Java 可执行文件的路径。例如,如果路径当前设置为“C:\WINDOWS\SYSTEM32”,则将您的路径更改为“C:\WINDOWS\SYSTEM32;c:\Program Files\java\jdk\bin”。

为 Windows 95/98/ME 设置路径

我们假设您已将 Java 安装在c:\Program Files\java\jdk目录中:

  • 编辑“C:\autoexec.bat”文件,并在末尾添加以下行:“SET PATH=%PATH%;C:\Program Files\java\jdk\bin”

为 Linux、UNIX、Solaris、FreeBSD 设置路径

环境变量 PATH 应设置为指向 Java 二进制文件安装的位置。如果您在执行此操作时遇到问题,请参阅您的 shell 文档。

例如,如果您使用 bash 作为您的 shell,则您将在“.bashrc”的末尾添加以下行:'export PATH=/path/to/java:$PATH'

流行的 Java 编辑器

要编写 Java 程序,您需要一个文本编辑器。市场上有很多复杂的 IDE 可供使用。但就目前而言,您可以考虑以下其中之一:

  • 记事本 - 在 Windows 机器上,您可以使用任何简单的文本编辑器,如记事本(本教程推荐使用),TextPad。

  • Netbeans - 它是一个开源且免费的 Java IDE,可以从 https://www.netbeans.org/index.html 下载。

  • Eclipse - 它也是一个由 Eclipse 开源社区开发的 Java IDE,可以从 https://www.eclipse.org/ 下载。

Google Guice 环境

下载最新版本的 Google Guice 和相关的 jar 文件。

在编写本教程时,我们已将它们复制到 C:\>Google 文件夹中。

操作系统 归档名称
Windows guice-4.1.0.jar;aopalliance-1.0.jar;guava-16.0.1.jar;javax.inject-1.jar
Linux guice-4.1.0.jar;aopalliance-1.0.jar;guava-16.0.1.jar;javax.inject-1.jar
Mac guice-4.1.0.jar;aopalliance-1.0.jar;guava-16.0.1.jar;javax.inject-1.jar

设置 CLASSPATH 变量

设置CLASSPATH环境变量以指向 Guice jar 文件的位置。假设您已将 Guice 和相关的 jar 文件存储在不同操作系统的 Google 文件夹中,如下所示。

操作系统 输出
Windows 将环境变量 CLASSPATH 设置为 %CLASSPATH%;C:\Google\guice-4.1.0.jar;C:\Google\aopalliance-1.0.jar;C:\Google\guava-16.0.1.jar;C:\Google\javax.inject-1.jar;.;
Linux export CLASSPATH=$CLASSPATH:Google/guice-4.1.0.jar:Google/aopalliance-1.0.jar:Google/guava-16.0.1.jar:Google/javax.inject-1.jar:.
Mac export CLASSPATH=$CLASSPATH:Google/guice-4.1.0.jar:Google/aopalliance-1.0.jar:Google/guava-16.0.1.jar:Google/javax.inject-1.jar:.

Google Guice - 第一个应用

让我们创建一个基于控制台的示例应用程序,我们将逐步演示使用 Guice 绑定机制进行依赖注入。

步骤 1:创建接口

//spell checker interface
interface SpellChecker {
   public void checkSpelling();
}

步骤 2:创建实现

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {
   @Override
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   } 
}

步骤 3:创建绑定模块

//Binding Module
class TextEditorModule extends AbstractModule {
   @Override
   protected void configure() {
      bind(SpellChecker.class).to(SpellCheckerImpl.class);
   } 
}

步骤 4:创建具有依赖关系的类

class TextEditor {
   private SpellChecker spellChecker;
   @Inject
   public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }
   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   }
}

步骤 5:创建 Injector

Injector injector = Guice.createInjector(new TextEditorModule());

步骤 6:获取依赖关系已满足的对象。

TextEditor editor = injector.getInstance(TextEditor.class);

步骤 7:使用该对象。

editor.makeSpellCheck(); 

完整示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck(); 
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   }
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {
      bind(SpellChecker.class).to(SpellCheckerImpl.class);
   } 
}

//spell checker interface
interface SpellChecker {
   public void checkSpelling();
}


//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   @Override
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   } 
}

输出

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.

Google Guice - 链接绑定

在链接绑定中,Guice 将类型映射到其实现。在下面的示例中,我们已将 SpellChecker 接口与其实现 SpellCheckerImpl 映射。

bind(SpellChecker.class).to(SpellCheckerImpl.class);

我们还可以将具体类映射到其子类。请参见下面的示例

bind(SpellCheckerImpl.class).to(WinWordSpellCheckerImpl.class);

在这里,我们已链接绑定。让我们在完整示例中查看结果。

完整示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck(); 
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   }
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {
      bind(SpellChecker.class).to(SpellCheckerImpl.class);
      bind(SpellCheckerImpl.class).to(WinWordSpellCheckerImpl.class);
   } 
}

//spell checker interface
interface SpellChecker {
   public void checkSpelling();
}


//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   @Override
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   } 
}

//subclass of SpellCheckerImpl
class WinWordSpellCheckerImpl extends SpellCheckerImpl{
   @Override
   public void checkSpelling() {
      System.out.println("Inside WinWordSpellCheckerImpl.checkSpelling." );
   } 
}

输出

编译并运行该文件,您将看到以下输出。

Inside WinWordSpellCheckerImpl.checkSpelling.

Google Guice - 绑定注解

我们可以将类型与其实现绑定。如果我们希望将类型与多个实现映射,我们也可以创建自定义注解。请参见下面的示例以了解该概念。

创建绑定注解

@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
@interface WinWord {}
  • @BindingAnnotation - 将注解标记为绑定注解。

  • @Target - 标记注解的适用性。

  • @Retention - 将注解的可用性标记为运行时。

使用绑定注解进行映射

bind(SpellChecker.class).annotatedWith(WinWord.class).to(WinWordSpellCheckerImpl.class);

使用绑定注解注入

@Inject
public TextEditor(@WinWord SpellChecker spellChecker) {
   this.spellChecker = spellChecker;
}

完整示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import java.lang.annotation.Target;

import com.google.inject.AbstractModule;
import com.google.inject.BindingAnnotation;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

import java.lang.annotation.Retention;

import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;

@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
@interface WinWord {}

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();     
   } 
}

class TextEditor {
   private SpellChecker spellChecker;   

   @Inject
   public TextEditor(@WinWord SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling(); 
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {
      bind(SpellChecker.class).annotatedWith(WinWord.class)
         .to(WinWordSpellCheckerImpl.class);    
   } 
}

//spell checker interface
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   @Override
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   } 
}

//subclass of SpellCheckerImpl
class WinWordSpellCheckerImpl extends SpellCheckerImpl{
   @Override
   public void checkSpelling() {
      System.out.println("Inside WinWordSpellCheckerImpl.checkSpelling." );
   } 
}

输出

编译并运行该文件,您将看到以下输出。

Inside WinWordSpellCheckerImpl.checkSpelling.

Google Guice - Named 绑定

Guice 还提供了另一种无需创建自定义注解即可映射绑定的方法。它允许使用 @Named 注解。

使用 named 注解进行映射

bind(SpellChecker.class).annotatedWith(Names.named("OpenOffice")).to(OpenOfficeWordSpellCheckerImpl.class);

使用 @Named 注解注入

@Inject
public TextEditor(@Named("OpenOffice") SpellChecker spellChecker) {
   this.spellChecker = spellChecker;
}

完整示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private SpellChecker spellChecker;
   

   @Inject
   public TextEditor(@Named("OpenOffice") SpellChecker spellChecker) {
      this.spellChecker = spellChecker;      
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling(); 
   }  
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {
      bind(SpellChecker.class).annotatedWith(Names.named("OpenOffice"))
         .to(OpenOfficeWordSpellCheckerImpl.class);
   } 
}

//spell checker interface
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   @Override
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   } 
}

//subclass of SpellCheckerImpl
class OpenOfficeWordSpellCheckerImpl extends SpellCheckerImpl{
   @Override
   public void checkSpelling() {
      System.out.println("Inside OpenOfficeWordSpellCheckerImpl.checkSpelling." );
   } 
}

输出

编译并运行该文件,您将看到以下输出。

Inside OpenOfficeWordSpellCheckerImpl.checkSpelling.

Google Guice - 常量绑定

Guice 提供了一种使用值对象或常量创建绑定的方法。考虑我们希望配置 JDBC url 的情况。

使用 @Named 注解注入

@Inject
public void connectDatabase(@Named("JBDC") String dbUrl) {
   //...
}

这可以使用 toInstance() 方法实现。

bind(String.class).annotatedWith(Names.named("JBDC")).toInstance("jdbc:mysql://:5326/emp");

完整示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeConnection();
   } 
}

class TextEditor {
   private String dbUrl;
   @Inject
   public TextEditor(@Named("JDBC") String dbUrl) {
      this.dbUrl = dbUrl;
   }

   public void makeConnection(){
      System.out.println(dbUrl);
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {
      bind(String.class)
         .annotatedWith(Names.named("JDBC"))
         .toInstance("jdbc:mysql://:5326/emp");
   } 
}

输出

编译并运行该文件,您将看到以下输出。

jdbc:mysql://:5326/emp

Google Guice - @Provides 注解

Guice 提供了一种使用 @provides 方法创建复杂对象绑定的方法。

@Provides
public SpellChecker provideSpellChecker(){
   String dbUrl = "jdbc:mysql://:5326/emp";
   String user = "user";
   int timeout = 100;
   SpellChecker SpellChecker = new SpellCheckerImpl(dbUrl, user, timeout);
   return SpellChecker;
}

此方法是绑定模块的一部分,并提供要映射的复杂对象。请参见下面的完整示例。

完整示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provides;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private SpellChecker spellChecker;
   @Inject
   public TextEditor( SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }
   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {} 

   @Provides
   public SpellChecker provideSpellChecker(){

      String dbUrl = "jdbc:mysql://:5326/emp";
      String user = "user";
      int timeout = 100;

      SpellChecker SpellChecker = new SpellCheckerImpl(dbUrl, user, timeout);
      return SpellChecker;
   }
}

//spell checker interface
interface SpellChecker {
public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   private String dbUrl;
   private String user;
   private Integer timeout;

   @Inject
   public SpellCheckerImpl(String dbUrl, 
      String user, 
      Integer timeout){
      this.dbUrl = dbUrl;
      this.user = user;
      this.timeout = timeout;
   } 

   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
      System.out.println(dbUrl);
      System.out.println(user);
      System.out.println(timeout);
   }
}

输出

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.
jdbc:mysql://:5326/emp
user
100

Google Guice - Provider 接口

随着 @provides 方法变得越来越复杂,这些方法可以使用 Provider 接口移动到单独的类中。

class SpellCheckerProvider implements Provider<SpellChecker>{
   @Override
   public SpellChecker get() {
      String dbUrl = "jdbc:mysql://:5326/emp";
      String user = "user";
      int timeout = 100;
      SpellChecker SpellChecker = new SpellCheckerImpl(dbUrl, user, timeout);
      return SpellChecker;
   } 
}

下一步是将 Provider 映射到类型。

bind(SpellChecker.class).toProvider(SpellCheckerProvider.class);

请参见下面的完整示例。

完整示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provider;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private SpellChecker spellChecker;
   @Inject
   public TextEditor( SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {
      bind(SpellChecker.class)
         .toProvider(SpellCheckerProvider.class);
   } 
}

//spell checker interface
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   private String dbUrl;
   private String user;
   private Integer timeout;

   @Inject
   public SpellCheckerImpl(String dbUrl, 
      String user, 
      Integer timeout){
      this.dbUrl = dbUrl;
      this.user = user;
      this.timeout = timeout;
   } 

   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
      System.out.println(dbUrl);
      System.out.println(user);
      System.out.println(timeout);
   }
}

class SpellCheckerProvider implements Provider<SpellChecker>{

   @Override
   public SpellChecker get() {
      String dbUrl = "jdbc:mysql://:5326/emp";
      String user = "user";
      int timeout = 100;

      SpellChecker SpellChecker = new SpellCheckerImpl(dbUrl, user, timeout);
      return SpellChecker;
   }
}

输出

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.
jdbc:mysql://:5326/emp
user
100

Google Guice - 构造函数绑定

Guice 提供了一种使用 toConstructor() 方法创建对象特定构造函数绑定的方法。

@Override
protected void configure() {
   try {
      bind(SpellChecker.class)
         .toConstructor(SpellCheckerImpl.class.getConstructor(String.class));
      } catch (NoSuchMethodException | SecurityException e) {
      System.out.println("Required constructor missing");
   } 
} 

请参见下面的完整示例。

完整示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private SpellChecker spellChecker;
   @Inject
   public TextEditor( SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {
      try {
         bind(SpellChecker.class)
            .toConstructor(SpellCheckerImpl.class.getConstructor(String.class));
      } catch (NoSuchMethodException | SecurityException e) {
         System.out.println("Required constructor missing");
      } 
      bind(String.class)
         .annotatedWith(Names.named("JDBC"))
         .toInstance("jdbc:mysql://:5326/emp");
   } 
}

//spell checker interface
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   private String dbUrl;

   public SpellCheckerImpl(){}

   public SpellCheckerImpl(@Named("JDBC") String dbUrl){
      this.dbUrl = dbUrl;
   } 

   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
      System.out.println(dbUrl); 
   }
}

输出

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.
jdbc:mysql://:5326/emp

Google Guice - 内置绑定

Guice 为java.util.logging.Logger类提供了内置绑定。Logger 的名称会自动设置为注入 Logger 的类的名称。请参见下面的示例。

示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import java.util.logging.Logger;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private Logger logger;

   @Inject
   public TextEditor( Logger logger) {
      this.logger = logger;
   }

   public void makeSpellCheck(){
      logger.info("In TextEditor.makeSpellCheck() method");
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {
   } 
}

输出

编译并运行该文件,您将看到以下输出。

Dec 20, 2017 12:51:05 PM TextEditor makeSpellCheck
INFO: In TextEditor.makeSpellCheck() method

Google Guice - 即时绑定

由于绑定是在绑定模块中定义的,因此 Guice 在需要注入依赖项时会使用它们。如果绑定不存在,它可以尝试创建即时绑定。绑定模块中存在的绑定称为显式绑定,优先级更高,而即时绑定称为隐式绑定。如果两种类型的绑定都存在,则考虑使用显式绑定进行映射。

以下是三种类型的即时绑定的示例。

绑定类型 描述
可注入的构造函数 非私有、无参数的构造函数有资格进行即时绑定。另一种方法是使用 @Inject 注解注释构造函数。
@ImplementatedBy 注解 @ImplementatedBy 注解告诉 Guice 实现类。在这种情况下,绑定模块中不需要绑定。
@ProvidedBy 注解 @ProvidedBy 注解告诉 Guice 实现类的提供者。在这种情况下,绑定模块中不需要绑定。

Guice - 可注入的构造函数

非私有、无参数的构造函数有资格进行即时绑定。另一种方法是使用 @Inject 注解注释构造函数。请参见示例

示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public TextEditor( SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() { 
      bind(SpellChecker.class).to(SpellCheckerImpl.class);
      bind(String.class)
         .annotatedWith(Names.named("JDBC"))
         .toInstance("jdbc:mysql://:5326/emp");
   } 
}

//spell checker interface
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   @Inject @Named("JDBC")
   private String dbUrl;

   public SpellCheckerImpl(){}

   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
      System.out.println(dbUrl); 
   }
}

输出

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.
jdbc:mysql://:5326/emp

Guice - @ImplementatedBy 注解

@ImplementatedBy 注解告诉 Guice 实现类。在这种情况下,绑定模块中不需要绑定。请参见示例

示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public TextEditor( SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() { 
      bind(String.class)
         .annotatedWith(Names.named("JDBC"))
         .toInstance("jdbc:mysql://:5326/emp");
   } 
}

@ImplementedBy(SpellCheckerImpl.class)
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   @Inject @Named("JDBC")
   private String dbUrl;

   public SpellCheckerImpl(){}

   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
      System.out.println(dbUrl); 
   }
}

输出

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.
jdbc:mysql://:5326/emp

Google Guice - @ProvidedBy 注解

@ProvidedBy 注解告诉 Guice 实现类的提供者。在这种情况下,绑定模块中不需要绑定。请参见示例

示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.ProvidedBy;
import com.google.inject.Provider;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private SpellChecker spellChecker;
   @Inject
   public TextEditor( SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {     
   } 
}

@ProvidedBy(SpellCheckerProvider.class)
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   private String dbUrl;
   private String user;
   private Integer timeout;

   @Inject
   public SpellCheckerImpl(String dbUrl, 
      String user, 
      Integer timeout){
      this.dbUrl = dbUrl;
      this.user = user;
      this.timeout = timeout;
   } 

   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
      System.out.println(dbUrl);
      System.out.println(user);
      System.out.println(timeout);
   }
}

class SpellCheckerProvider implements Provider<SpellChecker>{

   @Override
   public SpellChecker get() {
      String dbUrl = "jdbc:mysql://:5326/emp";
      String user = "user";
      int timeout = 100;

      SpellChecker SpellChecker = new SpellCheckerImpl(dbUrl, user, timeout);
      return SpellChecker;
   }
}

输出

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.
jdbc:mysql://:5326/emp
user
100

Google Guice - 构造函数注入

注入是将依赖项注入对象的过程。构造函数注入非常常见。在此过程中,依赖项作为参数注入到构造函数中。请参见下面的示例。

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck(); 
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   }
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {
      bind(SpellChecker.class).to(SpellCheckerImpl.class);
   } 
}

//spell checker interface
interface SpellChecker {
   public void checkSpelling();
}


//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   @Override
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   } 
}

输出

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.

Google Guice - 方法注入

注入是将依赖项注入对象的过程。方法注入用于将值对象作为依赖项设置到对象中。请参见下面的示例。

示例

创建一个名为 GuiceTester 的 Java 类。

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public TextEditor( SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() { 
      bind(String.class)
         .annotatedWith(Names.named("JDBC"))
         .toInstance("jdbc:mysql://:5326/emp");
   } 
}

@ImplementedBy(SpellCheckerImpl.class)
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {
 
   private String dbUrl;

   public SpellCheckerImpl(){}
   
   @Inject 
   public void setDbUrl(@Named("JDBC") String dbUrl){
      this.dbUrl = dbUrl;
   }

   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
      System.out.println(dbUrl); 
   }
}

输出

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.
jdbc:mysql://:5326/emp

Google Guice - 字段注入

注入是将依赖项注入对象的过程。字段注入用于将值对象作为依赖项设置到对象的字段中。请参见下面的示例。

示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public TextEditor( SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() { 
      bind(String.class)
         .annotatedWith(Names.named("JDBC"))
         .toInstance("jdbc:mysql://:5326/emp");
   } 
}

@ImplementedBy(SpellCheckerImpl.class)
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   @Inject @Named("JDBC")
   private String dbUrl;

   public SpellCheckerImpl(){}

   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
      System.out.println(dbUrl); 
   }
}

输出

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.
jdbc:mysql://:5326/emp

Google Guice - 可选注入

注入是将依赖项注入对象的过程。可选注入意味着如果存在则注入依赖项。方法和字段注入可以是可选依赖项,如果依赖项不存在,则应具有一些默认值。请参见下面的示例。

示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.name.Named;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public TextEditor( SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {} 
}

@ImplementedBy(SpellCheckerImpl.class)
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   private String dbUrl = "jdbc:mysql://:5326/emp";

   public SpellCheckerImpl(){}
   
   @Inject(optional=true)
   public void setDbUrl(@Named("JDBC") String dbUrl){
      this.dbUrl = dbUrl;
   }

   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
      System.out.println(dbUrl); 
   }
}

输出

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.
jdbc:mysql://:5326/emp

Google Guice - 按需注入

注入是将依赖项注入对象的过程。方法和字段注入可用于使用injector.injectMembers()方法使用现有对象进行初始化。请参见下面的示例。

示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.Injector;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      SpellChecker spellChecker = new SpellCheckerImpl();
      injector.injectMembers(spellChecker);
      
      TextEditor editor = injector.getInstance(TextEditor.class);     
      editor.makeSpellCheck();
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public void setSpellChecker(SpellChecker spellChecker){
   this.spellChecker = spellChecker;
   }
   public TextEditor() { }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {      
   } 
}

@ImplementedBy(SpellCheckerImpl.class)
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   public SpellCheckerImpl(){}
   
   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
   }
}

编译并运行该文件,您将看到以下输出。

Inside checkSpelling.

Google Guice - 作用域

Guice 在提供值时每次都会返回一个新实例,这是其默认行为。它可以通过作用域进行配置。以下是 Guice 支持的作用域

  • @Singleton - 应用程序生命周期内单个实例。@Singleton 对象需要是线程安全的。

  • @SessionScoped - Web 应用程序特定会话的单个实例。@SessionScoped 对象需要是线程安全的。

  • @RequestScoped - Web 应用程序特定请求的单个实例。@RequestScoped 对象不需要是线程安全的。

应用作用域的方式。

以下是应用作用域的方式。

在类级别

@Singleton
class SpellCheckerImpl implements SpellChecker {

   public SpellCheckerImpl(){}
   
   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
   }
}

在配置级别

   bind(SpellChecker.class).to(SpellCheckerImpl.class).in(Singleton.class);

在方法级别

@Provides @Singleton
public SpellChecker provideSpellChecker(){

   String dbUrl = "jdbc:mysql://:5326/emp";
   String user = "user";
   int timeout = 100;

   SpellChecker SpellChecker = new SpellCheckerImpl(dbUrl, user, timeout);
   return SpellChecker;
}

示例

让我们看看类级别作用域的实际应用。

使用 @Singleton 注解的结果

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      SpellChecker spellChecker = new SpellCheckerImpl();
      injector.injectMembers(spellChecker);

      TextEditor editor = injector.getInstance(TextEditor.class);     
      System.out.println(editor.getSpellCheckerId());

      TextEditor editor1 = injector.getInstance(TextEditor.class);     
      System.out.println(editor1.getSpellCheckerId());
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public void setSpellChecker(SpellChecker spellChecker){
      this.spellChecker = spellChecker;
   }
   public TextEditor() { }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 

   public double getSpellCheckerId(){
      return spellChecker.getId();
   }
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {   
      bind(SpellChecker.class).to(SpellCheckerImpl.class);
   } 
}

interface SpellChecker {
   public double getId();
   public void checkSpelling();
}

@Singleton
class SpellCheckerImpl implements SpellChecker {

   double id; 
   public SpellCheckerImpl(){
      id = Math.random();    
   }

   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
   }

   @Override
   public double getId() { 
      return id;
   }
}

编译并运行文件,您可能会看到以下输出。

0.3055839187063575
0.3055839187063575

不使用 @Singleton 注解的结果

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      SpellChecker spellChecker = new SpellCheckerImpl();
      injector.injectMembers(spellChecker);

      TextEditor editor = injector.getInstance(TextEditor.class);     
      System.out.println(editor.getSpellCheckerId());

      TextEditor editor1 = injector.getInstance(TextEditor.class);     
      System.out.println(editor1.getSpellCheckerId());
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public void setSpellChecker(SpellChecker spellChecker){
      this.spellChecker = spellChecker;
   }
   public TextEditor() { }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   } 

   public double getSpellCheckerId(){
      return spellChecker.getId();
   }
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {   
      bind(SpellChecker.class).to(SpellCheckerImpl.class);
   } 
}

interface SpellChecker {
   public double getId();
   public void checkSpelling();
}

class SpellCheckerImpl implements SpellChecker {

   double id; 
   public SpellCheckerImpl(){
      id = Math.random();    
   }

   @Override
   public void checkSpelling() { 
      System.out.println("Inside checkSpelling." );
   }

   @Override
   public double getId() { 
      return id;
   }
}

编译并运行文件,您可能会看到以下输出。

0.556007079571739
0.22095011760351602

Google Guice - AOP

AOP,面向切面编程,它将程序逻辑分解成不同的部分,称为关注点。跨越应用程序多个点的函数称为横切关注点,这些横切关注点在概念上与应用程序的业务逻辑是分开的。日志记录、审计、声明式事务、安全、缓存等是各种常见的良好方面示例。

OOP 中模块化的关键单元是类,而在 AOP 中,模块化的单元是方面。依赖注入帮助您将应用程序对象彼此解耦,而 AOP 帮助您将横切关注点与受其影响的对象解耦。AOP 就像 Perl、.NET、Java 等编程语言中的触发器。Guice 提供拦截器来拦截应用程序。例如,当执行方法时,您可以在方法执行之前或之后添加额外的功能。

重要类

  • Matcher - Matcher 是一个接口,用于接受或拒绝值。在 Guice AOP 中,我们需要两个匹配器:一个用于定义哪些类参与,另一个用于这些类的​​方法。

  • MethodInterceptor - 当调用匹配的方法时,会执行 MethodInterceptors。它们可以检查调用:方法、其参数和接收实例。我们可以执行横切逻辑,然后委托给底层方法。最后,我们可以检查返回值或异常并返回。

示例

创建一个名为 GuiceTester 的 Java 类。

GuiceTester.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.matcher.Matchers;

public class GuiceTester {
   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new TextEditorModule());
      TextEditor editor = injector.getInstance(TextEditor.class);
      editor.makeSpellCheck(); 
   } 
}

class TextEditor {
   private SpellChecker spellChecker;

   @Inject
   public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }

   public void makeSpellCheck(){
      spellChecker.checkSpelling();
   }
}

//Binding Module
class TextEditorModule extends AbstractModule {

   @Override
   protected void configure() {
      bind(SpellChecker.class).to(SpellCheckerImpl.class);
      bindInterceptor(Matchers.any(), 
         Matchers.annotatedWith(CallTracker.class), 
         new CallTrackerService());
   } 
}

//spell checker interface
interface SpellChecker {
   public void checkSpelling();
}

//spell checker implementation
class SpellCheckerImpl implements SpellChecker {

   @Override @CallTracker
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   } 
}

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
@interface CallTracker {}

class CallTrackerService implements MethodInterceptor  {

   @Override
   public Object invoke(MethodInvocation invocation) throws Throwable {
      System.out.println("Before " + invocation.getMethod().getName());
      Object result = invocation.proceed();
      System.out.println("After " + invocation.getMethod().getName());
      return result;
   }
}

编译并运行文件,您可能会看到以下输出。

Before checkSpelling
Inside checkSpelling.
After checkSpelling
广告

© . All rights reserved.