Java 鬆綁 (二):利用 Package 與動態載入徹底鬆綁
在先前的例子裡,我們利用 Java 多型的技巧,來鬆綁類別之間的依賴關係。但在這個例子裡,變更實作類別時,還是需要重新編譯程式,還是不夠方便!!
有沒有更棒的方法呢??
有的。
動態載入
Java 中的 java.lang.Class
類別有提供一個 forName()
的靜態方法 (Static Method),可以讓我們請 JVM 動態的載入指定的類別。使用 Class.forName()
時,你必須指定要動態載入的類別之 FQCN,如果 JVM 可以找得到該類別,就可在執行時期載入我們所需的類別。
實作的方法如下示範:
package org.cdchen.serviceloaders.apps; import org.cdchen.serviceloaders.GreetingService; public class TraditionalDynamicLoadingMain { @SuppressWarnings("unchecked") public static void main(String[] args) { try { Class<GreetingService> clz = (Class<GreetingService>) Class.forName("org.cdchen.serviceloaders.impls.HiGreetingService"); GreetingService service = clz.newInstance(); GreetingServiceUtil.callService(service); } catch (Exception e) { e.printStackTrace(); } } }
實務上當然不會像這個範例一樣,直接在程式中指定要載入的類別 FQCN,畢竟這樣未來需要更改類別時,還得重新編譯一次,就失去了彈性的要求。解決這個問題的方法,有很多種;其中最常見的一種,就是把要實作的類別,寫在某一個檔案裡。然後在呼叫端 (Caller) 讀入該檔案,以便取得設定中的類別 FQCN,最後再呼叫 Class.forName()
。不過,我不想這麼麻煩來處理,下列的示範使用 System.getProperty()
的方式,取得名為 greetingservice.impls
的 Property,作為類別的名稱:
package org.cdchen.serviceloaders.apps; import org.cdchen.serviceloaders.GreetingService; public class TraditionalDynamicLoadingMain2 { @SuppressWarnings("unchecked") public static void main(String[] args) { String className = System.getProperty("greetingservice.impls"); try { Class<GreetingService> clz = (Class<GreetingService>) Class.forName(className); GreetingService service = clz.newInstance(); GreetingServiceUtil.callService(service); } catch (Exception e) { e.printStackTrace(); } } }
這樣之後,以後執行這個 Main Class 時:
$ java -Dgreetingservice.impls=org.cdchen.serviceloaders.impls.HiGreetingService \ org.cdchen.serviceloader.apps.TraditionalDynamicLoadingMain2
只需要變更 -Dgreetingservice.impls
的值即可在執行期間動態載入指定的類別。
再鬆綁
截至目前為止,我們都是在同一個 Package (注意,這裡的 Package 是指 Jar 檔) 中來實作鬆綁的策略。雖然可以達到鬆綁依賴關係的目的,但如果未來增加或修改了實作的類別,都還得重新製作與部署 Package (注意:Jar 檔)。為了能夠把鬆綁的原則發揮到淋漓盡致,我們也可以考慮把介面與實作分散在不同的 Package (注意:還是 Jar 檔)。例如:
apis-0.0.1-SNAPSHOT.jar
提供介面。以本文的例子來說,就是org.cdchen.serviceloaders.GreetingService
這個介面。imps-0.0.1-SNAPSHOT.jar
提供實作的類別,以本文的範例來說,就是org.cdchen.serviceloaders.impls
這個 Package (這裡的 Package 是指 Java 的 Package) 中所有的類別。
透過這樣的方式,只要在執行 JVM 的時候,配合 -cp
參數,指定實作的 Package (Jar 檔) 名稱即可:
$ java -cp impls-0.0.1-SNAPSHOT.jar:apis-0.0.1-SNAPSHOT.jar \ -Dgreetingservice.impls=org.cdchen.serviceloaders.impls.HiGreetingService \ org.cdchen.serviceloader.apps.TraditionalDynamicLoadingMain2
如此一來,爾後若有新增或修改實作類別,只需重新部署 impls-*.jar
檔案即可。
這樣是不是更迷人??
這篇內容的 Trackback 網址:
- cdchen 的 BLOG
- 如果想要發表回應,請先登入 或 註冊。