簡單的 ServiceLoader 示例

ServiceLoader 是一種簡單易用的內建機制,用於動態載入介面實現。使用服務載入器 - 提供即時(但不是佈線)的方法 - 可以在 Java SE 中構建簡單的依賴注入機制。使用 ServiceLoader 介面和實現分離變得自然,程式可以方便地擴充套件。實際上,很多 Java API 都是基於 ServiceLoader 實現的

基本概念是

  • 在服務介面上執行
  • 通過 ServiceLoader 獲取服務的實現
  • 提供服務的實現

讓我們從介面開始,把它放在一個 jar 中,例如 accounting-api.jar

package example;

public interface AccountingService {

  long getBalance();
}

現在我們在名為 accounting-impl.jar 的 jar 中提供該服務的實現,其中包含服務的實現

package example.impl;
import example.AccountingService;

public interface DefaultAccountingService implements AccouningService {

  public long getBalance() {
    return balanceFromDB();
  }

  private long balanceFromDB(){
    ...
  }
}

此外,accounting-impl.jar 包含一個檔案,宣告此 jar 提供了 AccountingService 的實現。該檔案必須具有以 META-INF/services/開頭的路徑,並且必須與介面的完全限定名稱具有相同的名稱 :

  • META-INF/services/example.AccountingService

該檔案的內容是實現的完全限定名稱:

example.impl.DefaultAccountingService

鑑於兩個 jar 都在程式的類路徑中,消耗 AccountingService,可以使用 ServiceLauncher 獲取服務的例項

ServiceLoader<AccountingService> loader = ServiceLoader.load(AccountingService.class)
AccountingService service = loader.next();
long balance = service.getBalance();

由於 ServiceLoaderIterable,它支援多個實現提供程式,程式可以從中選擇:

ServiceLoader<AccountingService> loader = ServiceLoader.load(AccountingService.class)
for(AccountingService service : loader) {
   //...
}

請注意,在呼叫 next() 時,將始終建立一個新例項。如果要重用例項,則必須使用 ServiceLoader 的 iterator() 方法或 for-each 迴圈,如上所示。