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.