Enterprise JavaBeans 技术一般分成三种核心类型的 bean:会话 bean、消息驱动 bean 和实体 bean。bean 还可以分成充当业务对象的 bean 和充当数据对象的 bean。会话 bean 和消息驱动 bean 是业务对象;实体 bean 是数据对象。大多数情况下,只需要将业务对象暴露给 Web 层(有时称为应用层),因为业务对象可以使用数据对象来处理数据存储。但在有些情况下,有必要允许用户直接访问和操作数据对象,这意味着要将实体 bean 暴露给 Web 层。这会使您的应用程序面临安全性威胁,而且随着您的应用程序的发展,还会导致杂乱无章的代码。
在这篇 EJB 最佳实践的专栏文章中,我们将讨论为什么绝对不可以将实体 bean 暴露给应用程序的 Web 层,以及为什么这是难以避免的。接着我将向您演示一个变通方法,它既能使您的实体 bean 更安全,又能使您的整个应用程序更有效率。
实体 bean 揭示了大量有关数据库底层结构的信息。因为每个 bean 都包含用于数据库中的各个字段的取值(accessor)和赋值(mutator)方法(即,
getxxx() 和
setxxx() ),而且因为方法名称通常与字段名称连在一起(
User bean 中的
getFirstName() 通常访问
Users表中的
firstName字段),所以从应用程序的实体 bean 推断这个应用程序的整个数据库结构是可能的。尽管在单个应用程序中这可能不是什么大问题,但您的 bean 常常会暴露给其它网络上另外的应用程序。在 Web 服务系统中尤其会发生这种情况,其中应用程序都是跨多个网络链接的。
除了存在使您数据库结构暴露给未知应用程序的明显危险之外,您还应该考虑当数据结构更改时会发生什么。因为实体 bean 与您的数据结构紧密地结合在一起,所以随着数据库表中列的更改或新列的添加,实体 bean 常常要随之更改。通过将您的实体 bean 暴露给应用层,可以使它们的方法名称可用,而且这些方法名称几乎总是被您的应用程序和外部应用程序合并到新的应用程序代码中。随着您的实体 bean 的更改以及发展,就会出现严重的代码混乱。
幸运的是,有一个设计模式让您允许用户访问数据对象,同时又不会将实体 bean 暴露给 Web 层。 会话虚包(Session Facade)模式在实体 bean 和应用程序客户机之间放置了一个会话 bean。当我通过这种方法使用会话 bean 时,我喜欢把它当作 管理器,因为它的任务是管理对其它实体的访问。
会话 bean 旨在充当业务逻辑和应用逻辑之间的接口。在我们的 工作示例的例子中,逻辑极其简单,而且它只调出一个底层实体 bean。然而在实际情况中,您可能会选择让会话 bean 管理数据验证、安全性或任何其它特定于业务的功能。通过将实体 bean 封装在会话 bean 中,您可以访问所有所需的业务功能,同时不会“污染”您的实体 bean 代码。
为了解决工作示例中的问题,您可以创建称为
MovieManager 的会话 bean。
MovieManager bean 将包含旧方法
getDirector() 和新方法
getDirectors() 。当添加了新方法时,它只是被“代理”到您的实体 bean。因为第一个方法在实体 bean 中不再可用,所以会话 bean 使用助手方法来隐藏它,如清单 1 所示:
清单 1. 隐藏已不使用的方法
public Person getDirector() {
// We can't call getDirector() any more on the entity bean
// Call the new method, through this manager
List directors = getDirectors();
// Return the first one in the list
return (Person)directors.item(0);
}
|
清单 1 的适用性不是特别健壮,但它获得了成功。因为隐藏了旧方法(而不是删除),所以所有与它相关的应用程序代码都一直存在。通过将助手方法放置在它所属的业务对象中,您还将它排斥在实体 bean 之外。解决了这个紧急的问题后,您可以选择将 bean 的客户机手工移植到新方法,或让助手方法一直处理移植工作。不管是哪种方法,都不会影响您的应用程序代码和您的客户机代码。
尽管上面的解决方案确实解决了更改管理的问题,但它不能消除安全性问题。您仍需要保护实体 bean(并由此保护您的数据结构),以免暴露给 Web 层。通过向会话 bean 添加一些简单的业务逻辑和数据操作功能,您不仅可以隐藏应用程序的数据结构,还可以提供对它所包含的信息的更复杂访问。
例如,随着应用程序的发展,您可能发现让用户依次访问各种数据对象(例如,导演、制片人、演员)的效率很低。因为这类信息几乎总是被放在一起,并一起使用,所以您可能发现重新确定会话 bean 的用途会很有帮助。您的会话 bean 将不包含
getDirector() 或
getDirectors() 方法,而是包含了如清单 2 所示的新的业务逻辑:
清单 2. 用会话 bean 掩盖数据结构
public List getCrew(String movieName)
throws NamingException, RemoteException {
List crew = new LinkedList();
EJBHomeFactory f = EJBHomeFactory.getInstance();
MovieHome movieHome =
(MovieHome)f.lookup("java:comp/env/ejb/Movie", MovieHome.class);
Movie movie = movieHome.findByName(movieName);
crew.add(movie.getDirectors());
crew.add(movie.getProducers());
crew.add(movie.getExecutiveProducers());
// and so on...
return crew;
}
public List getCast(String movieName)
throws NamingException, RemoteException {
List cast = new LinkedList();
EJBHomeFactory f = EJBHomeFactory.getInstance();
MovieHome movieHome =
(MovieHome)f.lookup("java:comp/env/ejb/Movie", MovieHome.class);
Movie movie = movieHome.findByName(movieName);
crew.add(movie.getActors());
crew.add(movie.getStandIns());
// and so on...
return cast;
}
|
通过分离不同的应用程序层,以及使用业务逻辑来处理数据操作,您既阻止了对实体 bean 直接而且可能不安全的访问,又为您的 Web 层创建了更有意义的方法集。本例中,会话虚包充当了实体 bean 的封装器以及真正的业务逻辑单元,从而将原始数据转变成有意义的信息。
会话虚包模式是许多其它设计模式的基本构件,其优点远远不止这里所讨论的。在 EJB 最佳实践的下一篇专栏文章中,我们将使用 本系列的第一篇技巧文章中研究的业务接口(Business Interface)模式,以及您在这里了解到的某些诀窍来进一步抽象出使用您应用程序中所有类型 EJB 组件的过程。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 查阅由 Brett McLaughlin 所著的完整的
EJB best practices
系列文章。
- 在 Java 架构设计师 Srikanth Shenoy 的“
Best practices in EJB exception handling”(
developerWorks,2002 年 5 月)一文中,他演示了如何编码以便在基于 EJB 技术的系统上更快地解决问题。
- Kyle Brown 在
WebSphere 开发者园地上发表了“
Rules and Patterns for Session Facades”一文(2001 年 6 月)。
- Sun Microsystems 的
EJB 技术主页是了解有关 EJB 技术信息的良好起点。
- 另一个极佳的参考资料是
TheServerSide.com,它提供了有关 J2EE 的文章和信息。
- 请参阅
developerWorks Java 专区教程页面,以获取与 EJB 技术和 J2EE 相关的免费教程的列表。
- 在
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 联系。