快精灵印艺坊 您身边的文印专家
广州名片 深圳名片 会员卡 贵宾卡 印刷 设计教程
产品展示 在线订购 会员中心 产品模板 设计指南 在线编辑
 首页 名片设计   CorelDRAW   Illustrator   AuotoCAD   Painter   其他软件   Photoshop   Fireworks   Flash  

 » 彩色名片
 » PVC卡
 » 彩色磁性卡
 » 彩页/画册
 » 个性印务
 » 彩色不干胶
 » 明信片
   » 明信片
   » 彩色书签
   » 门挂
 » 其他产品与服务
   » 创业锦囊
   » 办公用品
     » 信封、信纸
     » 便签纸、斜面纸砖
     » 无碳复印纸
   » 海报
   » 大篇幅印刷
     » KT板
     » 海报
     » 横幅

用 JAVA 反射构建更通用的业务委派

尽管业务委派类确实给您的企业 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 组件时,我们常常跨越远程接口、业务接口、实现类和现在的业务委派类来复制许多方式。我们中的许多人喜欢在编辑器窗口和 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 的业务委派
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&acute;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() 和获得结果之间,您会感到一些延时。前一篇技巧文章中展示的静态业务委派类是更快的解决方案,但它使您的业务层和技术层的耦合程度比您所希望的要高。因此,在权衡这两个选择时,选择哪一个要根据设计或性能而定。当应用程序的设计比整体性能更重要时,动态委派是更好的选择。当性能是更重要的因素时,业务委派是更好的选择。
返回类别: 教程
上一教程: JBUILDER2005实战JSP之程序功能介绍(1)
下一教程: JSP分页显示

您可以阅读与"用 JAVA 反射构建更通用的业务委派"相关的教程:
· 构建自己的基于Java的超级计算机
· 构建高性能J2EE应用的10个技巧
· JAVA REFLECTION (JAVA反射)
· Java性能优化通用篇
· 学习心得:Java为什么支持反射机制?
    微笑服务 优质保证 索取样品