[转载]使用通用 SQL 实体 EJB 包装器来简化 EJB 开发

使用通用 SQL 实体 EJB 包装器来简化 EJB 开发


Enterprise JavaBeans(EJB)的设计旨在减少企业应用程序的开发时间,但是有可能因为滥用 EJB 而导致最终开发出来的应用程序难以维护而且性能低下。本文描述一种简化自下而上 EJB 开发的编码技术,该技术允许端到端代码生成。本文提供的示例都基于 IBM DB2 通用数据库 和 WebSphere Studio。

重要:在阅读本文之前请先阅读 免责声明

引言

Enterprise JavaBeans™(EJB)的设计旨在帮助显著地减少企业应用程序的开发时间。让我们做一个简短的回顾,有两种 EJB:提供业务逻辑的 会话 bean和封装业务数据的 实体 bean。 会话 bean 类似于数据库存储过程,实体 bean 类似于数据库结果集。EJB 为远程访问、可扩展性、安全性和事务提供内置功能部件。这些内置功能部件是需要开销的。一个只执行一个 SQL 语句的简单存储过程是一个小的源文件。执行相同任务的简单会话 EJB 需要 10 个以上的类文件。很容易因为滥用 EJB 而导致最终开发出来的应用程序难以维护而且性能低下。

Java™ 2 Enterprise Edition(J2EE)使用实体 EJB 来为底层的关系数据库系统提供抽象层。然而,实体 EJB 的接口使数据库应用程序的只使用 SQL 语句的进程变得复杂。特别是在自下而上开发项目和旧的数据库开发中,设计是面向数据库的,也就是说架构师应该从 SQL 调用的角度,而不是从 EJB 工厂和对象的角度来考虑问题。

我提出了一个使实体 EJB 的使用变得通用的设计模式来简化 EJB 开发。该设计模式保留了直观的 SQL 接口,但提供了 EJB 的可重用性和内置分布式事务支持。它可以处理许多常见情况。因为比较通用,所以它可以用于自动代码生成。给定一个数据库表,自下而上方案可以生成从容器管 理的持久性(Container-Managed Persistence,CMP)实体 bean、会话 bean 直到 Java Server Page(JSP)甚至 Web 服务的代码。


blue_rule.gif
c.gif
c.gif
u_bold.gif回页首


通用实体 EJB 包装器

通用 SQL 实体 EJB 包装器是助手类,它操作实体 EJB 工厂和接口以达到通过提供直观的 SQL 接口来执行某些 SQL 语句的目标。

图 1说 明典型的 EJB 外观(facade)模式。EJB 会话外观模式提供了到服务器端组件的稳定的高级网关。模型层包括关系数据库和一系列实体 EJB。每个实体 bean 是一行数据的抽象;关系数据库负责持久存储。业务层包括会话 EJB,这个会话 EJB 是对实体 bean 的客户机。会话 bean 中定义的任何方法都是事务。会话 bean 中的方法是您实现业务逻辑的地方。


图 1. EJB 编程模型
EJB 编程模型

实体 bean 中的函数是通过 bean 的 homeremote接口被调用的,它涉及到对以下包的广泛使用:

javax.ejb.*
java.rmi.*
javax.naming.*

实体 bean 的 home接口允许客户机创建新的实体 bean 实例、查找现有的实体 bean 并除去实体 bean 实例。实体 bean 的 remote接口允许客户机调用 bean 的业务方法,例如 setter 和 getter。所有这些都由容器转换为 JDBC 调用。要确保 EJB 的正确使用并确保有效生成的 SQL 语句,您可能需要参考 IBM Developer Domain 中的最佳实践文章 [ 参考资料 1]。

图 2显 示了通用 SQL EJB 包装器是如何简化这些任务的。有了助手类,数据库开发变得更直观和更通用。该类主要是进行函数的相互映射。EJB 容器将 SQL JDBC 调用映射到实体 bean 中的复杂的方法矩阵,SQL EJB 助手类将方法映射回 SQL 包装器。


图 2. 使用 SQL EJB 包装器的 EJB 编程模型
使用 SQL EJB 包装器的 EJB 编程模型

在 会话 bean 中的业务方法中,获取通用 SQL EJB 包装器的句柄,并调用由包装器提供的期望的 SQL 方法。SQL EJB 助手方法将操作实体 bean 接口以执行期望的 SQL 语句。而且,当外观 bean 和实体 bean 在同一台机器上时,SQL EJB 包装器还可以利用实体 bean 的本地接口。所有最佳实践都可以封装在包装器中。这些对于业务逻辑开发者都是透明的。


blue_rule.gif
c.gif
c.gif
u_bold.gif回页首


用法示例 1:应用程序开发

在本节中,我将把如何使用当前技术来开发一个单一事务和如何使用通用实体 bean 包装器来执行相同的任务进行比较。

当前技术

让我们看一下在 WebSphere® Studio 的 Application Developer 配置中开发一个单一事务所涉及的步骤:

  1. 使用 Enterprise Bean 向导来生成实体 bean。
  2. 使用 Enterprise Bean 向导来生成外观会话 bean。
  3. 实现 EJB 助手代码。
  4. 开发事务逻辑。

使 用当前技术,Websphere Studio 可以方便地生成实体 bean 对象层和空的外观会话 bean,如上述步骤 1和 2 所示。WebSphere Studio 可以通过简单地浏览 DB2® Universal Database™ (UDB) JDBC 元数据支持来检索数据库模式。

步骤 3 是 EJB 助手代码的开发。 清单 1是从 WebSphere Performance Benchmark Sample [ 参考资料 2] 中抽取的助手代码。在这里,您作为开发者,将编写例程来处理 EJB 上下文、home 查找和高速缓存。这还将涉及复杂的异常处理和内联文档。


清单 1. EJB 助手代码
public class TradeStaticContext
{
private static boolean verbose = true;
static InitialContext _initContext = null;
static QuoteHome _marketHome = null;
public static QuoteHome getQuoteHome()
{
if (_initContext == null)
{ setContext(); }
return _marketHome;
}
private static synchronized void setContext()
{
InitialContext localContext = null;
//Trade 2.037 - Fixes startup race condition -
//if _initContext has been set, another thread got here first
//and has already setup the EJB Homes
if (_initContext != null)
return;
if (verbose)
{
System.out.println( "TradeStaticContext.setContext: Setting context" );
}
try
{
localContext = new InitialContext();
}
catch (Exception me)
{
System.out.println(
"TradeStaticContext.setContext: Get InitialContext failed!!");
me.printStackTrace();
}
try
{
Object obj = null;
//?
obj = localContext.lookup("java:comp/env/ejb/Quote");
_marketHome =
(QuoteHome) javax.rmi.PortableRemoteObject.narrow(obj, QuoteHome.class);
// Trade 2.037: Set _initContext after all EJB Homes have been setup to avoid
race condition
_initContext = localContext;
}
catch (Exception me)
{
System.out.println("TradeStaticContext.setContext: Lookup Homes failed!");
me.printStackTrace();
_initContext = null;
}
//?
if (_marketHome == null)
{
System.out.println(
"TradeStaticContext.setContext: Exception creating QuoteHome");
_initContext = null;
}
}
}

步骤 4 是您实现事务逻辑的地方。事务的主体放在会话 bean 中。某些助手函数被调用以使编码更容易,如 清单 2所示。


清单 2. 会话 bean 中的事务逻辑
public class TradeBean implements SessionBean
{
public QuoteObject getQuote(String symbol)
throws RemoteException, TradeException
{
//?
Quote quote = findQuote(symbol);
}
private Quote findQuote(String symbol)
throws RemoteException, TradeException
{
//?
QuoteHome qhome = TradeStaticContext.getQuoteHome();
retval = qhome.findByPrimaryKey(new QuoteKey(symbol));
}
}

很显然,一个简单的事务(对底层数据库的一个单一的 SELECT 语句)在 EJB 编程模型中也是有意义的任务。

通用 EJB 包装器技术

让我们来看一下使用通用 SQL 实体 EJB 包装器来完成相同任务的步骤:

  1. 使用 Enterprise Bean 向导来生成实体 bean。
  2. 开发(或生成)通用 SQL 实体 EJB 包装器代码。
  3. 使用 Enterprise Bean 向导来生成外观会话 bean。
  4. 填写外观会话 bean 中的业务逻辑。

类似的,Websphere Studio 可以方便地生成实体 bean 对象层和空的外观会话 bean,如上述步骤 1 和 3 所示。WebSphere Studio 可以通过简单地浏览 DB2 JDBC 元数据支持来检索数据库模式。

基 于我们所学的最佳实践和课程,我们知道可以通过开发 Eclipse 插件来完成步骤 2 ,该插件生成通用 SQL 实体 EJB 包装器代码。(样本代码将在下一篇文章中提供。)这可以显著地提高生产率。通过使用通用 SQL 实体 EJB 包装器,仅需一些鼠标点击,您就可以生成为 Universal Test Client(UTC)准备的 J2EE 应用程序,这其中包括对任何表 Select、Insert、Delete 和 Update 缺省方法。开发者现在可以定制代码并定义他们自己的业务方法。

在步骤 4 中,业务事务可以放在外观会话 bean 的主体中。在 清单 3中,添加了 getQuote 事务。


清单 3. 将 getQuote 事务添加至外观会话 bean
public class RegistryFacadeBean implements SessionBean
{
// Add user defined business methods here
public QuoteData getQuote(String symbol)
{
QuoteWrapper wQuote = new QuoteCMPWrapper();
Vector vQuote = wQuote.
Select( symbol, null, null );
if( vQuote.size() == 0 )
return null;
else
return ( QuoteData ) vQuote.get( 0 );
}
}

当自下而上工作时,getQuote 更自然地作为 SELECT 实现。要这么做,只需获取生成的模型助手(即实体 bean 包装器)的句柄,并调用 Select() 方法。

在本实现中,Select() 方法不仅仅是一个包装器。它还是一个 SELECT 模板,支持各种可能的“ = ”布尔谓词组合。例如,语句: Select( symbol, null, null )

将变换为以下 EJBQL:

Select object(q) from Quote q where q.symbol=?l 

如果您将它更改为:

Select( symbol, price, null ) 

那么执行以下语句:

Select object(q) from Quote q where q.symbol=?l and q.price=?2

以此类推。

IBM® AccessBean 还避免了客户机程序的管理企业 bean 生命周期的复杂性。查看 AccessBeans 和 SQL 包装器接口如何一起工作以简化自下而上 EJB 开发是很有趣的事情。


blue_rule.gif
c.gif
c.gif
u_bold.gif回页首


用法示例 2:生成 EJB Web 页

WebSphere Studio 有很出色的 Database Web Pages 向导。给定一个 SQL 语句,该向导可以生成能够通过 JDBC 访问数据库的 HTML 和 JSP 代码。如果您想在 EJB(而不是 JDBC)中这么做,您可能需要利用通用实体 EJB 包装器。本节描述使用通用 SQL 实体 EJB 包装器如何将端到端 EJB Web 页生成为样本代码。

样本数据库

这是自下而上代码生成,数据库是起点。下面的示例说明如何使用通用 SQL 实体 EJB 包装器从 DB2 数据库表开始生成端到端自下而上代码。让我们将以下表定义作为代码生成示例的起点。

Column                         Type      Type
name schema name
------------------------------ --------- ------------
USERID SYSIBM VARCHAR
PASSWORD SYSIBM VARCHAR
STATUS SYSIBM INTEGER

实体 bean

使用 Enterprise Bean 向导来生成上面显示的表的实体 bean。实体 bean 是一行数据的抽象。表列被映射到容器管理的字段。


清单 4. 生成实体 bean
public class RegistryBean implements EntityBean
{
// Container managed fields
public java.lang.String userid;
public java.lang.String password;
public java.lang.Integer status;
//...
}

通用 SQL 实体 EJB 包装器

SQL 实体 EJB 包装器由我们在 用法示例 1中提到的 Eclipse 插件为实体 bean 生成。包装器实现 Select、Insert、Delete 和 Update 方法接口。


清单 5. SQL 实体 EJB
public interface RegistryWrapper
{
public Vector Select( RegistryData dRegistry );
public Vector SelectForUpdate( RegistryData dRegistry );
public void Insert( RegistryData dRegistry );
public void Delete();
public void Update( RegistryData dRegistry );
}

RegistryData 类是数据类。在我们的例子中,它用作 SQL 谓词的占位符以及结果集的占位符,该结果集从会话 bean 和实体 bean 传入/传出。

外观会话 bean

Enterprise Bean 向导可以为实体 bean 生成外观会话 bean。会话 bean 是实现业务方法的地方。在缺省情况下,生成 Select、Insert、Delete 和 Update 业务方法。实体 bean 包装器在关系数据库业务方法中被调用。


清单 6. 实体 bean 的外观 bean
public class RegistryFacadeBean implements SessionBean
{
public Vector Select( RegistryData dRegistry ) {
RegistryWrapper wRegistry
= new RegistryCMPWrapper();
return wRegistry.Select( dRegistry );
}

public Vector SelectForUpdate( RegistryData dRegistry )
{ /*...*/ }

public void Insert( RegistryData dRegistry ) { /*...*/ }

public void Delete() { /*...*/ }

public void Update( RegistryData dRegistry ) { /*...*/ }
// Add user defined business methods here
}

清单 6的示例中,生成的 Select() 业务方法是通过简单地调用 Registry 实体 bean 包装器中的 Select() 方法来完成的。Insert、Delete 和 Update 业务方法的实现是类似的。

客户机

然后,外观会话 bean 中的 SQL 方法可以提交到控制器层和/或表示层以用于测试目的。这并不局限于 servlet 和 JSP。没有任何限制阻止方法提交到诸如 J2EE 应用程序、Java Applet 和 Web 服务之类的客户机。


blue_rule.gif
c.gif
c.gif
u_bold.gif回页首


结束语

通 用 SQL 实体 EJB 包装器不仅简化自下而上 EJB 数据库开发,而且在许多情况下允许端到端代码生成。如示例中所示,通用提供了使用生成代码的机会,而且封装显著地提高了自下而上 EJB 编程和旧的数据库开发的生产率。该实现可以由 WebSphere 和 DB2 UDB 使用。下一篇文章将详细讨论设计模式的实际使用。


blue_rule.gif
c.gif
c.gif
u_bold.gif回页首


免责声明

本 文包含样本代码。IBM 授予您(“被许可方”)使用这个样本代码的非专有的、版权免费的许可证。然而,样本代码是以“按现状”的基础提供的,不附有任何形式的(不论是明示的,还 是默示的)保证,包括对适销性、适用于某特定用途或非侵权性的默示保证。IBM 及其许可方不对被许可方使用该软件所导致的任何损失负责。任何情况下,无论损失是如何发生的,也不管责任条款怎样,IBM 或其许可方都不对由使用该软件或不能使用该软件所引起的收入的减少、利润的损失或数据的丢失,或者直接的、间接的、特殊的、由此产生的、附带的损失或惩罚 性的损失赔偿负责,即使 IBM 已经被明确告知此类损害的可能性,也是如此。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-130619/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/374079/viewspace-130619/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值