Cd Chen's Services

ba ba ba la~~

Java 鬆綁 (三):利用 ServiceLoader 實作動態載入

在前兩篇文章中,我們看到了如何利用 Java 多型的技巧,鬆綁類別之間的關係;也看到如何透過動態載入的技巧,來鬆綁 Package。不過還不是很完美,至少我是這樣認為。

在「Java 鬆綁 (二):利用 Package 與動態載入徹底鬆綁」這篇文章中,係利用 Class.forName() 這個古老的方法來實作動態載入的功能,個人覺得非常的麻煩且缺乏彈性。比較理想的作法,係利用 Java EE 或者 SpingFramework 提供的 CDI (Contexts & Dependency Injection) 來實作這樣的要求。

不過 Java EE 容器雖然是 Java 世界中的標準,但重量級的執行環境,對於一個小的專案來說,非常的不值得;而 SpingFramework 雖然夠輕量化 (但近期的發展也趨向於重量),但卻不是標準的作法,實作與部署時必須考慮執行的環境中是否提供所需的條件。

所幸,Java 6 中提供了一個 java.util.ServiceLoader 類別,可以輔助我們簡化鬆綁的動作。

JAR 檔案的要求

要透過 java.util.ServiceLoader 來鬆綁 Package 時,你必須先在製作 Jar 檔前,在 META-INF/services/ 目錄中,儲存一個文字檔,其檔案名稱必須為介面的 FQCN,而內容則為該 Jar 檔案中實作該介面的類別之 FQCN。

例如,以前文的例子,我在 impls-*.jar 檔案中,建立下列的目錄結構:

  + <ROOT>
      + META-INF/
          + services/
              - org.cdchen.serviceloaders.GreetingService

並在 META-INF/services/org.cdchen.serviceloaders.GreetingService 檔案中,定義下列的內容:

# 一行一個實作的類別之 FQCN.
org.cdchen.serviceloaders.impls.HiGreetingService
org.cdchen.serviceloaders.impls.HasEatingService

改寫呼叫端

接著,我們換用 java.util.ServiceLoader 來實作動態組入的功能吧:

package org.cdchen.serviceloaders.apps;

import java.util.ServiceLoader;

import org.cdchen.serviceloaders.GreetingService;


public class ServiceLoaderMain {
	public static void main(String[] args) {
		// 載入 ServiceLoader.
		ServiceLoader<GreetingService> serviceLoader = ServiceLoader.load(GreetingService.class);
		
		// 遊走所有 service 物件.
		for (GreetingService service : serviceLoader) {
			GreetingServiceUtil.callService(service);
		}
	}
}

沒錯,就這麼簡單!! 與前文的 TraditionalDynamicLoadingMain 相比,是否更簡潔一些??

執行

準備就緒後,如果要執行這個案例,我們只需要在啟動 JVM 時,指定 -cp 參數即可:

$ java -cp apis-0.0.1-SNAPSHOT.jar:impls-0.0.1-SNAPSHOP.jar \
    org.cdchen.serviceloaders.apps.ServiceLoaderMain

就是這麼簡單,這麼愉快!! 

這篇內容的 Trackback 網址:

http://cdchen.idv.tw/trackback/1060
附加檔案大小
serviceloader-labs-0.0.1-SNAPSHOT.tar_.gz4.22 KB