dev2dev 首页 > 资源中心 > 技术文章
使用 EJBGen:"一个对三个"
开发WebLogic Server上的EJB时,您是否对那些Java文件以及相关的部署描述符感到头痛?很多工具可以帮助您开发bean代码,使用特殊的Javadoc注释来定义其他接口(Home,Remote)中的内容,以及定制出XML部署描述符(ejb-jar.xml,weblogic-ejb-jar.xml)的内容。但使用了这个工具后,您就会立即明白仅用一个Java源文件来表示EJB是多么简洁。
EJBGen 简介
本文中我们将介绍用于生成兼容WebLogic Server
6.1 EJB的工具,即EJBGen,它是由BEA WebLogic架构师Cedric Beust
开发的(http://www.beust.com/cedric/ejbgen)。它可以很容易地添加到你的 WebLogic上的应用中,且是IDE无关的 —— 仅需要在bean类中添加一些Javadoc标签。令人遗憾的是,此工具是不开放源代码的,因为它是由Cedric单独开发的,但是只要您加入邮件列表,就可以与他联系。无论是发出请求还是发现bug,Credric都会在短期内对这些进行处理。如果您需要开放源代码解决方案,则可以使用XDoclet (http://sourceforge.net/projects/xdoclet),它是从JBoss创始人Rickard Oberg所写的EJBDoclet发展而来的。
在本文中,我创建了一组WebLogic Server
6.1上可部署的EJB,表示简单的Order系统。其中有两个实体bean,代表一个订单及它的相关项。将使用EJB 2.0 CMP关系,允许我们从订单EJB对这些项进行访问。我们还有一个会话bean,它操作这些实体bean以便完成工作。
使用EJBGen
EJBGen允许您将EJB信息放在Javadoc标签中,这些标签嵌入在bean类中。特殊标签格式如下:
/**
* @ejbgen:tagname attribute = value attribute2 = value2 ...
*/
|
根据标签类型的不同,这些@ejbgen标签或者放在类级别,或者放在方法级别。在类级别,您可以声明EJB的名称、JNDI名称和实体bean的属性。方法级别属性标记给定方法的信息。最常使用的标签是组成Remote或Local接口的方法所使用的标签(使用@ejbgen:remote-method或@ejbgen:local-method)。
/**
* @ejbgen:remote-method
*/
public String viewMaxOrders() {
|
创建了bean类并且在源码中插入了Javadoc标签之后,可以通过Javadoc客户端运行EJBGen了:
% javadoc -docletpath /path/to/ejbgen.jar
-doclet EJBGen YourEJBs.java
|
还有命令行选项可以对EJBGen生成文件的方式进行调整。其中许多选项都使您可以更改不同元素的前缀和后缀。
要生成名为FooRemote.java而不是Foo.java的远程接口,运行以下命令(注意 –remoteSuffix):
% javadoc -docletpath ejbgen.jar -doclet EJBGen
-remoteSuffix Remote FooEJB.java
|
EJBGen站点提供了所有命令行选项的文档。
EJBGen 功能
EJBGen 还有以下功能:
·
包含EJB 2.0 全部功能(本地接口/CMP关系/消息驱动bean)
·
生成在WebLogic Server
6+ 上可部署的代码和部署描述符
·
可以生成实体Bean的值对象
·
属性文件:可以在bean类内定义和使用属性。通过 { property name }方式使用属性
·
支持Javadoc标签继承。基本适配器类可以设置标准值,然后实际的bean继承行为以及方法
·
生成ANT构建文件
如果生成ANT构建文件,运行EJBGen后,可以运行
% ant -buildfile ejbgen-build.xml
|
·
ant.buildFileName:buildfile的名称
·
ant.projectName:项目的名称
·
ant.docletPath:ejbgen.jar的路径
创建使用Javadoc标签的会话bean。现在我们看一个实际的例子,先是操作实体bean的会话bean。OrderViewerEJB.java将具有以下方法:
·
viewMaxOrders():返回最大数量的订单,其将是,以显示我们在类级别javadoc注释中对它们的设置 。
·
viewOrders():返回系统中的订单。
·
addOrder(orderId, orderBy, orderName):插入订单条目 。
·
addOrderItem(orderID, itemID, itemName, amount):这将为所给订单插入一项 。
·
deleteOrders():删除所有订单及其中的项 。
类级别定义
在类级别,我们需要定义这是一个会话bean的事实,其相关信息为:JNDI名称;EJB对实体bean的本地引用;和环境entries。
标签:@ejbgen:session
此处仅需要的属性是将bean的名称告诉EJBGen。我们还定义自由内存池中最大数量的bean(WebLogic缓存信息),及默认事务属性将是“Required”。
/**
* OrderViewer Bean views orders:
*
* @ejbgen:session
* ejb-name = OrderViewer
* max-beans-in-free-pool = 100
* default-transaction = Required
*
* ... other tags ...
*/
public class OrderViewerEJB implements SessionBean {
|
表1中显示了ejbgen:session标签的所有属性。
标签:@ejbgen:jndi-name
这个标签非常重要;它不仅定义JNDI名称,而且EJBGen也通过这个标签知道是否生成远程接口、本地接口,还是这两个接口都生成或都不生成!因为我们想将会话bean公开给远程客户端,所以我们将使用远程属性:
/**
* OrderViewer Bean views orders:
*
* ... other tags ...
*
* @ejbgen:jndi-name
* remote = ejbgenexamples.OrderViewer
*
* ... other tags ...
*/
public class OrderViewerEJB implements SessionBean {
|
对于本地接口,我们将添加属性“local = local-jndi-name”。
标签:@ejbgen:ejb-local-ref
我们的OrderViewer将使用实体bean说明订单和订单项。EJB 2.0引进了“本地接口”概念,它强迫组件在本地VM中“谈话”,而不越过远程边界。当使用实体bean时,最佳实践是在本地将会话bean(可以远程的)与实体bean一起使用。我们将分别定义对两个实体bean的本地引用(清单1)。
清单1
/**
* OrderViewer Bean views orders:
*
* ... other tags ...
*
* @ejbgen:ejb-local-ref
* home = ejbgenexamples.OrderLocalHome
* local = ejbgenexamples.OrderLocal
* jndi-name = ejbgenexamples.OrderLocalHome
* name = ejb/OrderHome
* type = Entity
*
* @ejbgen:ejb-local-ref
* home = ejbgenexamples.OrderItemLocalHome
* local = ejbgenexamples.OrderItemLocal
* jndi-name = ejbgenexamples.OrderItemLocalHome
* name = ejb/OrderItemHome
* type = Entity
*
* ... other tags ...
*/
public class OrderViewerEJB implements SessionBean {
|
使用这些本地引用,我们可以通过查询“java: comp/env/
<name>”来查询OrderLocal Home,从而获得对Home接口的访问权:
OrderLocalHome orderHome = (OrderLocalHome) new
InitialContext().lookup("java:/comp/env/ejb/Order-Home");
|
要使用远程接口引用EJB,使用@ejbgen:ejb-ref标签。
标签:@ejbgen:env-entry
要定义环境entries,使用ejbgen:env-entry标签。我们将定义环境条目保持最大数量订单的整数值:
/**
* OrderViewer Bean views orders:
*
* ... other tags ...
*
* @ejbgen:env-entry
* name = maxOrders
* type = java.lang.Integer
* value = 10
*
* ... other tags ...
*/
public class OrderViewerEJB implements SessionBean {
|
注意,类型必须给完整的(比如是java. lang.Integer,而不是Integer)。
方法级别定义
我们想对远程客户端将可以使用的所有方法进行标记。或者,您还可以使用方法的事务属性的值(即覆盖我们在类级别定义的默认值)和单独的级别。这里我们标记addOrder()方法:
/**
* Add an order
*
* @ejbgen:remote-method
*/
public void addOrder(Integer id, String orderBy, String name)
|
我们将看到实体bean将标记它们的方法@ejbgen:local-method。现在我们就完成了会话bean的创建!
创建OrderItem实体Bean
使用实体bean与使用会话bean相似。其中包括几个不同的类级别标签;我们将标签容器应该管理的字段及主键。将生成OrderItem实体,其包括三个字段 – itemid、itemname和itemamount – 这些字段将是持久的。
数据库表还将包含ORDER_ID,这是Order实体中的外键(稍后讨论)。现在我们将忽略OrderItem将与Order有关系这个事实。
类级别定义
在类级别,我们将定义实体定义、JNDI名称和实体finder签名,并且创建数据库中的表。
标签:@ejbgen:entity
像会话bean一样,我们需要定义实体bean的名称,可以定义诸如默认事务值等属性。我们还需要定义数据库中表的名称、主键类别和要使用的数据源:
/**
* @ejbgen:entity
* ejb-name = OrderItemEJB
* data-source-name = orderPool
* table-name = OrderItems
* prim-key-class = java.lang.Integer
* default-transaction = Required
*
* ... other tags ...
*/
public abstract class OrderItemEJB implements EntityBean {
|
表2中显示了ejbgen:entity标签的所有属性。
标签:@ejbgen:jndi-name
这个标签与会话相同,但是因为我们使用实体,所以将仅创建本地接口:
/**
* ... other tags ...
*
* @ejbgen:jndi-name
* local = ejbgenexamples.OrderItemLocalHome
*
* ... other tags ...
|
标签:@ejbgen:finder
每个finder方法都必须有一个ejbgen:finder标签。您必须指定方法签名,包括您可能要抛出的任何例外。而且,还要给出您希望使用的EJB Query Language语句。我们将定义findItemsByName()方法,它检索具有所给名称的每一项:
/**
* @ejbgen:finder
* signature = "Collection findItemsByName(String name)"
* ejb-ql = "WHERE name = ?1"
|
标签:@ejbgen: create-default-dbms-tables
如果进行开发,可以使WebLogic创建数据库表:
* @ejbgen:create-default-dbms-tables
|
方法级别定义
所有抽象的get()方法都必须标记为容器管理的持久字段,我们提供列名映射。必须标记为主键,而且如果要想能够从组件接口调用这些方法,我们还必须对接口进行标记(远程或本地)。下面是OrderItem的主键:
/**
* @ejbgen:cmp-field column = id
* @ejbgen:local-method
* @ejbgen:primkey-field
*/
public abstract Integer getId();
public abstract void setId(Integer id);
|
创建Order实体bean并将其与OrderItem相关联
WebLogic Server 6.1 支持EJB 2.0关系,其他许多J2EE服务器没有这个功能。然而,WebLogic Server6.1没有部署描述符工具来部署CMP关系实体(XML必须手动操作),所以我们将使用EJBGen的功能来完成此项工作。
我们将有一个一对多的关系,在这个关系中一个订单可以有多个关联项。在订单EJB中,我们能够通过getItems()获得订单的集合,从集合中我们可以通过OrderLocal getOrder()返回订单。像定义这些抽象的方法,我们需要在每一类中配置ejbgen:relation标签(Order-EJB和OrderItemEJB)。创建这个关系的步骤如下所示:
1.
OrderItem:配置ejbgen:relation标签
2.
OrderItem:创建容器管理的关系
3.
Order:配置ejbgen:relation标签
4.
Order:创建容器管理的关系
OrderItem:配置 ejbgen:
relation 标签
此项是关系中“多”的一方。关系双方共享同一名称,target-ejb是要使用此关系的bean的名称。因为我们有target-ejb属性,您可以将所有关系标签放入一个EJB bean类中。因为多重属性,我们将告诉EJBGen这些相关的外键列和映射到容器管理的关系的字段。删除订单时,我们希望相关的订单项能自动删除,这样就有了cascade-delete选项的需求:
* @ejbgen:relation
* multiplicity = many
* name = OrderCanHaveMultipleItems
* target-ejb = OrderItemEJB
* fk-column = order_id
* cmr-field = order
* cascade-delete = True
|
OrderItem:创建容器管理的关系
我们可以从订单EJB中的订单对象得到此订单。标记CMR字段并将其声明为本地方法:
/**
* @ejbgen:cmr-field
* @ejbgen:local-method
*/
public abstract OrderLocal getOrder();
public abstract void setOrder(OrderLocal order);
|
Order:配置ejbgen:relation标签
此Order是关系中“一”的一方。此关系必须有相同的关系名称:
* @ejbgen:relation
* multiplicity = one
* name = OrderCanHaveMultipleItems
* target-ejb = OrderEJB
|
Order:创建容器管理的关系
因为一个订单有许多返回值,我们使用OrderItems的集合:
/**
* @ejbgen:cmr-field
* @ejbgen:local-method
*/
public abstract Collection getItems();
public abstract void setItems(Collection items);
|
如果您曾经使用过CMP关系,您可能已经多少感到厌烦了。然而通过EJBGen创建CMP关系相当容易。我从来不想手动构建关系的XML。我想使用GUI构建关系,或者可以使用EJBGen。要想进一步使用EJBGen,可以使用能够构建EJBGen可识别类的GUI。请查看免费软件Middlegen (http://boss.bekk.no/boss/middlegen/)。
部署系统
现在我们有三个Java源文件:OrderEJB.java、OrderItemEJB.java和OrderViewerEJB.java。从这些文件我们将使用EJBGen生成接口和XML部署描述符。下面的build脚本将打包一个ejb-jar文件:
javadoc -docletpath c:\ejbgen\ejbgen.jar
-doclet EJBGen ejbgenexamples\Order*EJB.java
cd ejbgenexamples
javac -classpath %CLASSPATH%;.. *.java
cd ..
mv *.xml META-INF
jar cvf c:\bea\wlserver6.1\config\
mydomain\applications\ejbgen.jar *
|
在运行应用程序前,我们必须先在应用服务器(WebLogic Server)上配置数据源,注意既“orderPool”。清单2显示了客户端的main()方法,其添加、查看、然后删除订单。
清单 2
public static void main(String[] args) throws Exception {
Context ic = getInitialContext();
OrderViewerHome home = (OrderViewerHome)
ic.lookup("ejbgenexamples.OrderViewer");
OrderViewer v = home.create();
System.out.println("Add Order");
v.addOrder(new Integer(1), "Dion", "Books");
v.addOrderItem(new Integer(1), new Integer(1),
"EJB v3", 36.55f);
v.addOrderItem(new Integer(1), new Integer(2),
"Mastering EJB", 45.95f);
System.out.println("The Max Orders: " + v.viewMaxOrders());
System.out.println("Display Orders:\n" + v.viewOrders() );
System.out.println("Delete Orders");
v.deleteOrders();
}
|
结束语
我们了解了使用EJBGen为WebLogic Server
6.1开发EJB的方法。此工具使我们可以每个EJB的生成仅使用一个文件来完成,而不需要开发三个Java文件和多个相关的部署描述符。它是一个非常简洁的预处理系统 —— 甚至还有可以生成EJBGen可识别代码的其他工具!
| 作者简介 |
|
Dion Almaer是Middleware Company (www.middleware-company.com) 的首席技术专家,该公司是国内领先的EJB/J2EE和B2B技术培训机构之一。Middleware Company还构建和维护一流的在线J2EE社区TheServerSide.com。 |
作者其它文章
|