帝国软件
  设为首页 加入收藏 关于我们
 
解密帝国网站管理系统
栏 目:
 
您的位置:首页 > 技术文档 > JAVA编程 >
EJB最佳实践:动态委派
作者:未知 发布时间:2005-03-12 来源:JSP天空网
用 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 组件时,我们经常跨越远程接口、业务接口、实现类和现在的业务委派类来复制许多方法。我们中的许多人喜欢在编辑器窗口和 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() 和获得结果之间,您会感到一些延时。前一篇技巧文章中展示的静态业务委派类是更快的解决方案,但它使您的业务层和技术层的耦合程度比您所希望的要高。因此,在权衡这两个选择时,选择哪一个要根据设计或性能而定。当应用程序的设计比整体性能更重要时,动态委派是更好的选择。当性能是更重要的因素时,业务委派是更好的选择。

您可能会发现自己正在将动态委派用于内部网应用程序,在内部网中,所有机器都在本地网络上,并且您会经常添加或更改功能。对于电子商业和面向顾客的应用程序,原始的业务委派可能是更好的选择。在这两种情况下,您现在都应该对业务委派及其工作原理有了更好的理解。好好玩,玩得开心点,我们网上再见!

参考资料

查看 Brett McLaughlin 撰写的完整 EJB best practices 系列。


请参阅 SUN 的 Java 反射文档以了解更多关于反射的知识。


Java 架构设计师 Srikanth Shenoy 在其文章“Best practices in EJB exception handling”(developerWorks,2002 年 5 月)中演示了如何在基于 EJB 的系统上进行编码以更快地解决问题。


Sun 的 EJB 技术主页是获取有关 EJB 技术信息的良好起点。


另一个很棒的参考资料来源 TheServerSide.com 提供了关于 J2EE 的文章和信息。


请参阅 developerWorks Java 技术教程页面,以获取关于 EJB 和 J2EE 的 developerWorks 免费教程的列表。


在 developerWorks Java 技术专区上,您可以找到多达数百篇的 Java 技术参考资料。

关于作者
Brett McLaughlin 从 Logo 时代(还记得那个小三角吗?)就开始从事计算机工作了。他现在专门研究用 Java 和 Java 相关技术构建应用程序基础结构。过去几年他一直在 Nextel Communications 和 Allegiance Telecom, Inc. 致力于实现这些基础结构。Brett 是 Java Apache 项目 Turbine 的共同创始人之一,该项目用 Java servlet 为 Web 应用程序开发构建可重用的组件体系结构。他还是 EJBoss 项目(一个开放源码的 EJB 应用程序服务器)和 Cocoon(一个开放源码的 XML Web 发布引擎)的志愿开发人员之一。可通过 brett@oreilly.com 与 Brett 联系。 
  
评论】【加入收藏夹】【 】【打印】【关闭
※ 相关链接
无相关信息

   栏目导行
  PHP编程
  ASP编程
  ASP.NET编程
  JAVA编程
   站点最新
·致合作伙伴的欢迎信
·媒体报道
·帝国软件合作伙伴计划协议
·放眼未来 帝国近期将有重大举措!
·PHPWind6.3.2版通行证发布
·帝国备份王2008版正式发布
·帝国备份王2008版发布
·phpcms2007转帝国CMS5.0程序发布
·dedecms5.1转帝国CMS5.0程序发布
·帝国网站管理系统V5.0商业购买说明
   类别最新
·谈谈JDBC
·JDBC专题介绍
·JDBC接口技术
·利用weblogic的POOL(连接池)连接
·Jsp中调用Oracle存储过程的小例子
·JSP数据库操作例程
·JSP数据库连接大全
·用连接池提高Servlet访问数据库的效
·一种简单JDBC连接池的实现
·数据库连接池Java实现小结
 
关于帝国 | 广告服务 | 联系我们 | 程序开发 | 网站地图 | 留言板 帝国网站管理系统