XDoclet:EJB开发好帮手

来源:互联网 发布:澳大利亚淘宝网 编辑:程序博客网 时间:2024/04/26 18:58
XDoclet:EJB开发好帮手

 2002-06-06 14:22:56

使用XDoclet,你能够在J2EE环境下更加高效地工作,你所看到的Bean以及Bean之间的关系将更加简单,许多繁杂的事情将远离你的EJB开发过程。本文讨论的是如何使用和扩展XDoclet。在这篇文章中,我们将创建一个使用Javadoc标记的会话Bean,然后利用XDoclet处理这个Bean。 

一、什么是XDoclet 

XDoclet从Rickard Oberg创建的EJBDoclet工具发展而来,它的设想很简单:避免为每个EJB提供多个文件,而是从单一Bean类文件中提供组件需要的所有信息。那么,这是如何实现的呢?Java没有.NET吹嘘的“属性”,但Java有Javadoc标记。我们可以把一个特殊的@标记放入Javadoc注释,然后让一个Doclet工具处理这些标记。由工具为指定的Bean生成合适的XML描述器文件和接口文件。XDoclet建立在EJBDoclet思想的基础上,但适用范围不再局限于EJB。现在,我们已经可以用XDoclet生成Web服务、Web应用描述器,甚至还可以对它进行扩展,满足自己的特殊需要。 

@标记有一个标准的格式,包含一个“名称空间”以及一个属于该名称空间的“标记名称”。标记的属性以“名字=值”的形式在标记中指定。下面是一个例子: 

/** 
* @namespace:tag name="value" name2="value2" ... 
*/ 

当前可用的名称空间包括: 
ejb 标准的EJB信息(非厂商私有的信息) 
jboss 面向JBoss应用服务器的信息。 
weblogic 面向BEA Weblogic应用服务器的信息。 
webSphere 面向IBM WebSphere应用服务器的信息。 
orion 面向Orion应用服务器(Oracle)的信息。 
castor 为Castor框架生成映射信息。 
mvcsoft 为MVCSoft EJB 2.0持久化管理器生成文件。 
soap 生成SOAP描述器。 
struts 生成struts-config.xml。 
web 为Web应用生成web.xml配置文件。 
jsp 生成标记库扩展描述器信息。 
从上面的清单可以看出,除了EJB之外,XDoclet还提供了许多其它方面的支持(因此它的名字也从EJBDoclet变成了XDcolet)。 

二、用Javadoc标记标注会话Bean 
前面我们讨论了XDoclet工具的基本情况,下面来看一个实例。我们从一个会话EJB开始。这个EJB是XBeans框架的一部分,但对于本文来说,Bean有什么样的功能其实无关紧要。我们关心的是如何在Bean类的基础上,用Javadoc标记进行适当的标注,然后用XDoclet生成我们需要的各种文件。 
ReceiverBean.java文件包含了一个documentReady(Document doc)方法,这个方法接收一个DOM文档并把它传递给链上面的下一个XBean。 

2.1 在类这一级上的定义 

在类这一层次上,我们必须定义: 
声明Bean的类型,本例是无状态会话Bean。
JNDI名称。 
环境变量。 
面向厂商的信息(例如WebLogic 缓冲池信息)。 

2.1.1 @ejb:bean标记 

该标记唯一必需的属性是把Bean的名字告诉XDoclet。此外,我们还将定义Bean的类型、JNDI名称和显示的名称(display-name): 
/** 
* This is the EJB Receiver Xbean 

* @ejb:bean type="Stateless" 
* name="ejbReceiver" 
* jndi-name="org.xbeans.ejb.receiver.Receiver" 
* display-name="EJB Receiver Xbean" 

* ... 其他javadoc标记 ... 
*/ 
public class ReceiverBean implements SessionBean, DOMSource { 

ejb:Bean标记最常用的属性是: 
name EJB的名字(用于描述器)。 
type 定义Bean的类型。对于会话Bean,Bean的类型是Stateful或者Stateless;对于实体Bean,它是CMP或BMP。 
jndi-name 提供Bean的JNDI名字,它将被用于厂商私有的部署描述器(用于远程接口)。 
local-jndi-name 与jndi-name相同,但用于本地接口。 
view-type 表示应当支持哪一种Bean的“视图”。可以是remote或local,或者both。 

要查看所有标记的完整说明,请访问XDoclet的文档。 

2.1.2 @ejb:env-entry标记 

这个标记定义了将在JNDI中通过java:comp/env上下文配置的环境变量。下面我们将定义一个环境变量,Bean用它来查找链上面的下一个XBean: 

/** 
* This is the EJB Receiver Xbean 

* ... 其他javadoc标记 ... 

* @ejb:env-entry name="channelBean" type="java.lang.String" 
* value="com.your.ChannelBean" 

* ... 其他javadoc标记 ... 
*/ 
public class ReceiverBean implements SessionBean, DOMSource { 

2.1.3 @weblogic:pool标记 
下面我们将配置面向特定厂商的缓冲池特征,为便于讨论,我们将使用WebLogic。为表示声明仅对特定厂商有效,我们先声明weblogic名称空间: 
/** 
* This is the EJB Receiver Xbean 

* ... 其他javadoc标记 ... 

* @weblogic:pool max-beans-in-free-pool="1000" 
* initial-beans-in-free-pool="10" 

* ... 其他javadoc标记 ... 
*/ 
public class ReceiverBean implements SessionBean, DOMSource { 

这个标记将在面向WebLogic的部署描述器(weblogic-ejb-jar.xml)中配置缓冲池参数。 
还有其他许多类这一级的标记,这些标记使得我们能够调整任何可以在部署描述器中指定的选项。下面概要地介绍了可能在部署过程中要用到的一些“标准”标记: 
@ejb:bean:唯一必需的标记,配置有关Bean的基本信息。 
@ejb:home:提供有关Home接口的信息。可以要求XDoclet扩展一个定制的接口,或者把接口放入指定的包,等等。 
@ejb:interface:类似于home标记,但用来配置与组件接口(远程的和/或本地的)有关的信息。 
@ejb:finder:在实体Bean Home接口上定义查找器方法。 
@ejb:select:在实体Bean Home接口上定义select方法。 
@ejb:pk:为实体Bean定义主键。XDoclet能够生成主键类。 
@ejb:data-object:数据对象(也就是值对象)可以通过这个标记自动生成。 
@ejb:ejb-ref:配置EJB引用。 
@ejb:ejb-external-ref:配置对其他应用中的EJB的引用,这里必需指定Bean的类型等信息。 
@ejb:resource-ref:配置资源引用。 
@ejb:security-role-ref:配置安全角色引用。 
@ejb:transaction:为当前Bean的Home接口和Remote接口中的所有方法定义事务属性。可以通过为单个方法提供的事务标记覆盖。 
@ejb:permission:允许role-name中指定的角色调用该Bean的Home接口和Remote接口中的所有方法。 
@ejb:security-identity:指定是否用调用者的安全标识符执行EJB的方法,还是用另外一个特定的安全标识符。 

2.2 在方法这一级上的定义 
下面我们来看看方法级的标记。要让某个方法成为远程接口的一部分,我们只需通过一个方法级的标记告诉XDoclet: 
/** 
* The method that the sender uses to pass the Document 

* @ejb:interface-method view-type="remote" 
*/ 
public void documentReady(Document incomingDocument) { 

这个标记经常要用到。一般地,我们依次检查Bean类里面每一个方法,如果某个方法应该让客户程序调用,则在该方法声明的前面加上这个标记。如果希望客户程序通过本地接口访问这个方法,只需把view-type值改成local就可以了。 
下面是另外几个常用的EJB方法级的标记: 
@ejb:relation:为EJB 2.0 CMP实体Bean定义一个关系。 
@ejb:home-method:把方法定义为ejbHome*方法。 
@ejb:pk-field:标示主键域。 
@ejb:transaction:为当前的方法定义事务行为(指定一个合法的事务属性:NotSupported,Supports,Required,RequiresNew,Mandatory,或者Never)。 
@ejb:permission:定义方法的许可权限(给出一个允许访问该方法的角色的列表,用逗号分隔)。 
三、运行XDoclet 
现在我们完成了为ReceiverBean.java加上XDoclet标记的工作。下面我们要运行XDoclet,让它为我们生成所有部署Bean时需要的文件。运行XDoclet工具最好的方式是通过Jakarta-Ant进行。Ant是一个广泛应用的Java构造系统,现在几乎每个人都在用它。关于Ant的详细说明,请参见Jakarta 网站。 
XDoclet的作者为我们编写好了可以直接放入Ant构造文件(build.xml)的Ant任务。任务主要分两类:ejbdoclet和webdoclet。由于我们正在处理的是一个EJB,下面我们来仔细地分析一下build文件里面的ejbdoclet部分: 
<target name="ejbdoclet" depends="prepare">
<taskdef name="ejbdoclet" classname="xdoclet.ejb.EjbDocletTask" classpath="${java.class.path};${xdoclet.jar.path};${log4j.jar.path};${ant.jar.path}"/>
<ejbdoclet sourcepath="${java.dir}" destdir="${generated.java.dir}" ejbspec="2.0">
<fileset dir="${java.dir}">
<include name="**/ReceiverBean.java" />
</fileset>

<remoteinterface/>
<homeinterface/>
<deploymentdescriptor destdir="${build.dir}/ejb/META-INF"/>

<jboss destdir="${build.dir}/ejb/META-INF" version="2.4" xmlencoding="UTF-8" />
<weblogic destdir="${build.dir}/ejb/META-INF" xmlencoding="UTF-8" validatexml="true"/>
<webSphere destdir="${build.dir}/ejb/META-INF" />
<orion destdir="${build.dir}/ejb/META-INF" />
</ejbdoclet>
</target>

这个文件片段包含了大量的信息,因此我们要把它分解开来,逐条讨论。 
3.1 <taskdef>标记 
首先,我们要告诉Ant构造系统有关<ejbdoclet/>标记的信息。我们定义了标记的名称,指定了实现该标记的类以及可供使用的CLASSPATH。在这里,我们利用了在build.xml文件的前面设置的指向各个库文件的属性: 
<taskdef name="ejbdoclet" classname="xdoclet.ejb.EjbDocletTask" classpath="${java.class.path};${xdoclet.jar.path};${log4j.jar.path};${ant.jar.path}"/>
3.2 <ejbdoclet>标记 
最外面的标记<ejbdoclet>告诉Ant运行EJBDoclet任务。我们在<ejbdoclet>标记中指定了代码的位置,在哪里生成XML描述器,以及我们遵从的EJB规范版本(同样,这里也使用了前面定义的属性): 
<ejbdoclet sourcepath="${java.dir}" destdir="${generated.java.dir}" ejbspec="2.0">

3.3 <fileset>标记 
<fileset>指令告诉<ejbdoclet>到哪里去寻找Bean代码。本例将在${java.dir}的子目录下寻找ReceiverBean.java: 
<fileset dir="${java.dir}">
<include name="**/ReceiverBean.java" />
</fileset>

3.4 标准标记:接口和XML部署描述器 
接下来的这组标记将确保XDoclet生成Remote接口、Home接口和标准XML部署描述器(ejb-jar.xml): 
<remoteinterface/>
<homeinterface/>
<deploymentdescriptor destdir="${build.dir}/ejb/META-INF"/>

3.5 面向厂商的标记:接口和XML部署描述器 
最后一组标记用来生成面向厂商的部署描述器。如果只在一种服务器上部署EJB,我们只需设置一项即可。但这里我们假设要让Xbean EJB能够部署到尽可能多的厂商的应用服务器上,所以要加入所有厂商的标记。能够在不了解这些应用服务器具体细节的情况下生成各种面向特定供应商的文件,真是一件美妙的事情! 
<jboss destdir="${build.dir}/ejb/META-INF" version="2.4" xmlencoding="UTF-8" />
<weblogic destdir="${build.dir}/ejb/META-INF" xmlencoding="UTF-8" validatexml="true"/>
<webSphere destdir="${build.dir}/ejb/META-INF" />
<orion destdir="${build.dir}/ejb/META-INF" />
现在,要为Xbean EJB生成各种文件,我们只需在build文件所在的目录执行Ant。运行Ant时必须保证Ant的库文件(ant.jar,jaxp.jar和XML解析器)以及xdoclet.jar文件都在CLASSPATH中。例如,假设在Windows环境中: 

% set CLASSPATH=%CLASSPATH%;c:/lib/ant.jar;c:/lib/jaxp.jar;c:/lib/xerces.jar; c:/lib/xdoclet.jar;c;/lib/log4j.jar;c:/lib/ejb.jar
% ant ejbdoclet 

请参见本文下载代码中完整的build.xml文件。 

四、XDoclet的可扩展性 
XDoclet具有很好的可扩展性。按照XDoclet的构造方式,我们可以修改描述器文件和接口文件的输出结果,通过它的简单的模板机制,我们还可以创建出自己的输出。每一个输出文件有一个对应的模板文件,模板文件以“.j”为扩展名,打开xdoclet.jar包可以看到许多这类摸板文件。每一个摸板文件包含一组XML标记,从这些XML标记简单的逻辑很容易推测出摸板的输出结果。下面是一个从现成EJB模板取出的简单例子,它将输出从@ejb:bean display-name属性取得的Bean的显示名字: 
<display-name>
<XDtClass:classTagValue tagName="ejb:bean" paramName="display-name"/>
</display-name>
classTagValue XML标记为显示指定标记的属性提供了一个简单的接口。还有其他一些标记,比如支持循环,允许检查某个标记是否存在,等等。不论是调整输出结果还是创建新的模板,XDoclet都提供了相应的支持。 
在前面的例子中,会话Bean利用@ejb:env-entry标记把环境变量channelBean的值设置为com.your.ChannelBean。我们是否真地想要在Bean类里面以硬编码的方式指定这类信息呢?应该不是。这里我们有两种选择:一种方案是在Ant的build脚本里面定义这个值。然后,如果部署时需要修改这个值,我们可以修改属性,再返回Ant。要进行这种修改,我们首先调整build.xml文件: 
<property name="env-channelBean" value="com.my.ChannelBean" />
然后修改Bean类文件: 
/**
* @ejb:env-entry name="channelBean" type="java.lang.String"
* value="${env-channelBean}"
*/

另外一种方案是利用合并点(Merge Point)。EJB环境变量有一个合并点,允许我们利用该能力加入自己的环境变量(类似于C语言的#include指令)。只要创建一个ejb-entries-<ejbName>.xml文件,模板机制就会引用它,它的内容将在最后输出的ejb-jar.xml中出现。
结束语:本文探讨了如何用XDoclet辅助EJB开发。XDoclet是一个免费的、源代码开放的工具,能够简化EJB开发过程,允许我们用单个Bean类文件包含所有Bean需要的信息,自动生成接口文件和描述器文件。XDoclet正在不断地发展,它的用途不再局限于EJB。能够标示出那些希望能够通过SOAP使用的方法、配置Web应用(即使是用于Struts)无疑令人兴奋,但随着时间的发展,更多的功能将不断涌现,甚至还有一些工具能够用来生成XDoclet标记,例如Middlegen code generation tool for EJB 2.0 Entity Beans。