用 Java 反射構建更通用的業務委派
Brett McLaughlin(brett@oreilly.com) 作家兼編輯,O'Reilly and Associates 2003 年 3 月
盡管業務委派類確實給您的企業 Java 設計帶來了激動人心的新靈活性,但為您應用程序中的每個會話 bean 都編碼一個業務委派還是太麻煩了。在 EJB 最佳實踐系列的這篇文章里,Brett McLaughlin 向您展示了如何創建業務委派類的更通用的版本:動態委派。
在上一篇技巧文章中,我們討論了如何用業務委派類(請不要與業務接口(Business Interface)模式相混淆)來訪問您的 EJB 組件。通過在客戶機代碼和 EJB 代碼之間插入業務委派類,我們可以將應用程序的 Web 層與 EJB 語義和業務邏輯隔離開來。
研究這類設計的一種方法是看它有多通用。先從一個應用程序入手,該應用程序中的業務邏輯和技術函數是緊密地交織在一起的,我們已經逐步分離出應用程序的不同層,并使用不同的技術來降低它們的相互依賴。在這樣做時,您應該會發現:應用程序底層結構越通用,則隨著時間的推移,它就會越健壯且可維護性越好。
在這篇技巧文章中,我們將繼續使用通用設計的思想。我們將從研究當前業務委派實現的限制入手,然后我將向您展示如何通過創建更通用的(因而不那么呆板)業務委派類實現來克服這些限制。
業務委派類:復習 回顧一下我們上個月討論的 Library bean 接口的業務委派類。
LibraryDelegate 類的大部分代碼只是復制了原始 Library bean 的方法。LibraryDelegate 添加了 init() 、destroy() 和構造器方法,然后用這些方法將任務委派給 Library bean。在這樣做時,委派充當 Web 層和企業 bean 之間的緩沖區。這里是原始 bean 的業務接口。
方法的繁殖 除非您考慮到多個會話 bean 有 10 個、20 個或更多方法,否則這種方法的問題并不明顯。實際上,找到擁有 50 個或更多方法的會話 bean 并不罕見!因為 bean 的業務接口必須包括該 bean 的所有方法,所以業務委派類也將這樣做。那會使代碼過于龐大,并很容易出錯。
您的輸入是否太快了? 在使用 EJB 組件時,我們經??缭竭h程接口、業務接口、實現類和現在的業務委派類來復制許多方法。我們中的許多人喜歡在編輯器窗口和 IDE 之間剪切和粘貼方法,而不是手工輸入它們,但請注意:按 Option+V 或 Control+V 會象手工輸入方法一樣容易出錯 — 您添加的方法越多,出錯的可能性就越大。通過仔細檢驗您是否正確地輸入了方法,以及是否按預期剪切和粘貼了它們,最終可以使您避免許多麻煩。 |
除了龐大的代碼之外,我們還必須考慮變化因素。因為 Delegate 類必須復制 bean 的所有方法,并且隨著時間推移,bean 不可避免地會發生變化,您會發現需要花費很多時間來將新的方法添加到 Delegate ,更別提重新編譯了,有可能還要測試新代碼。
就其本身而言,這看起來似乎不是很嚴重的問題。但假如我們開始使用業務委派類來從技術基礎結構(在本文是指 EJB 組件)中抽象業務和表示邏輯呢。如果更改遠程接口需要對業務委派進行更改,那么,實際上,我們的業務委派仍然與底層組件聯系在一起。
我們需要更好的方法,您說是不是。確實有更好的方法。
動態委派 解決方案是使用動態委派,而它又使用 Java 反射(reflection)。您可以使委派動態地調用目標 EJB 組件的遠程接口上的方法(通過 Java Reflection API),而不必將每個業務方法硬編碼到委派中。這樣允許徹底消除來自遠程接口的耦合,因為,為 bean 的業務或遠程接口添加方法時不需要在業務委派中進行相應更改。使用動態委派還使得更改您的技術基礎結構更為容易。從遠程接口和 EJB 技術遷移到另一種技術(如 Java Data Objects,JDO)只需要更改委派的 init() 方法。所有其它方法調用將繼續通過 bean 的接口進行委派,并且可以繼續使用無需進一步更改。清單 1 顯示了 Library 業務委派的動態版本: 清單 1. Library bean 的業務委派
clearcase/" target="_blank" >cccccc border=1>
package com.ibm.library;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;
import javax.ejb.CreateException;
import javax.naming.NamingException;
public class LibraryDelegate implements ILibrary {
private ILibrary library;
private Map availableMethods;
public LibraryDelegate() {
init();
}
public void init() {
// Look up and obtain our session bean
try {
LibraryHome libraryHome =
(LibraryHome)EJBHomeFactory.getInstance().lookup(
"java:comp/env/ejb/LibraryHome", LibraryHome.class);
library = libraryHome.create();
// Get the methods available for use in proxying
availableMethods = new HashMap();
Method[] methods = ILibrary.class.getMethods();
for (int i=0; i<methods.length; i++) {
availableMethods.put(methods[i].getName(),
methods[i]);
}
} catch (NamingException e) {
throw new RuntimeException(e);
} catch (CreateException e) {
throw new RuntimeException(e);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
// All the hard-coded methods are removed
public Object
invoke(Object proxy, Method method, Object[] args)
throws Throwable{
try {
// See if this is init() or destroy()
if (method.getName().equals("init")) {
init();
return null;
} else if (method.getName().equals("destroy")) {
destroy();
return null;
} else {
Method method =
(Method)availableMethods.get(method.getName());
// See if we found anything
if (method != null) {
return method.invoke(library, args);
} else {
throw new
NoSuchMethodException("The Library does not " +
"support the " + method.getName() +" method.");
}
}
} catch (InvocationTargetException e) {
// We don't support throwing RuntimeExceptions from EJBs
// directly
if (e.getTargetException() instanceof RemoteException) {
throw new RuntimeException(e);
} else {
throw e.getTargetException();
}
}
}
public void destroy() {
// In this case, do nothing
}
}
|
動態委派出色地解決了委派、bean 及其業務接口之間的耦合問題。但是,它并不是完美的解決方案,也不會總是最好的解決方案。雖然您從這種方法中獲得了極大的靈活性,但也付出了性能代價。Java 反射并不十分快,因此在調用 invoke() 和獲得結果之間,您會感到一些延時。前一篇技巧文章中展示的靜態業務委派類是更快的解決方案,但它使您的業務層和技術層的耦合程度比您所希望的要高。因此,在權衡這兩個選擇時,選擇哪一個要根據設計或性能而定。當應用程序的設計比整體性能更重要時,動態委派是更好的選擇。當性能是更重要的因素時,業務委派是更好的選擇。
您可能會發現自己正在將動態委派用于內部網應用程序,在內部網中,所有機器都在本地網絡上,并且您會經常添加或更改功能。對于電子商業和面向顧客的應用程序,原始的業務委派可能是更好的選擇。在這兩種情況下,您現在都應該對業務委派及其工作原理有了更好的理解。好好玩,玩得開心點,我們網上再見!
|