如何使用XDoclet来简化EJB的开发

    根据EJB的规范,有些代码可以从Bean代码推导出来,如Home,Remote接口代码,而类似于ejb-jar.xml这样的Deployment Descriptor配置文件,如果让人手工输入也是一件很烦人的事情。XDoclet恰好能够解决这样的问题,XDoclet是一个开源的code generation engine. 它可以在JAVA中采用面向属性的编程。简单通俗的讲,你在JAVA代码中加入一些元数据,类似于JavaDoc标签,XDoclet就可以解析这样的源文件,然后根据源文件和元数据来产生指定的代码文件、XML文件。特别对于EJB,你可以只需要维护单个EJB源文件,其他文件如HOME,REMOTE都由XDoclet自动产生,这可以极大的减少你的开发时间。

     XDoclet可以作为ANT的一个编译部分来被调用,这样,由ANT在编译之前先调用XDoclet自动产生所需的文件,然后再编译,打包,部署。下面我以stateless session bean作为示范例子,XDoclet目前版本只支持到EJB 2.0,该例子代码规范遵从EJB 2.0,环境和工具如下:

 

JRE: 1.6.0_07                 http://www.java.com/en/download/manual.jsp

开发工具: Eclipse v3.5.0   http://download.eclipse.org/eclipse/downloads/

编译部署: ANT v1.7.1        http://ant.apache.org/bindownload.cgi

EJB服务器: jboss-4.2.3.GA   http://www.jboss.com/

XDoclet  v1.2.3                http://xdoclet.sourceforge.net/xdoclet/install.html

 

 

(1)在Eclipse中创建一个新项目Calculator

(2)创建一个sessionBean -- CalculatorBean.java

 

package org.jboss.tutorial.stateless.bean;

import javax.ejb.SessionBean;

/**
 *
 *
 * @ejb.bean name="Calculator" type="Stateless" view-type="remote"
 *           jndi-name="CalculatorBean/re"
 *
 * @ejb.transaction-type type="Container"
 *
 * @ejb.transaction type="Required"
 *
 */
public abstract class CalculatorBean implements SessionBean
{
 /**
     * @ejb.interface-method
     */
   public int add(int x, int y)
   {
      return x + y;
   }

   /**
    * @ejb.interface-method
    */
   public int subtract(int x, int y)
   {
      return x - y;
   }
   
  
}

 

注:在类定义的注释中有@ejb.bean ,@ejb.transaction-type 之类的元数据,在方法前的注释中有@ejb.interface-method,这些都是XDoclet中定义的元数据,具体的作用可以参考XDoclet的文档,这里了解EJB的朋友应该不难从单词意义上去理解它。

 

(3)创建用于ANT的build.xml文件 

 

 注意:脚本里有个 env.JBOSS_HOME变量,这要求你必须在环境变量里加入一个JBOSS_HOME,它的值指向jboss的安装目录。

请注意观察红色字体部分的脚本,在执行compile目标之前,将调用XDoclet, 所以在这个文件里必须指定XDoclet的安装目录。如果你

在自己的电脑上调试时,要注意XDoclet的安装目录是否正确。在这个例子代码中,XDoclet会在目标目录中产生HOME,REMOTE,SessionBean,Deployment Descriptor等文件,包括针对jboss的deploy文件。

<?xml version="1.0"?>

<!-- ======================================================================= -->
<!-- JBoss build file                                                       -->
<!-- ======================================================================= -->

<project name="JBoss" default="ejbjar" basedir=".">

   <property environment="env"/>
   <property name="src.dir" value="${basedir}/src"/>
   <property name="jboss.home" value="${env.JBOSS_HOME}"/>
   <property name="jboss.server.config" value="default"/>
   <property name="build.dir" value="${basedir}/build"/>
   <property name="build.classes.dir" value="${build.dir}/classes"/>
   <property name="build.src.dir" value="${build.dir}/src"/>
   <property name="build.artifact" value="jboss-ejb3-tutorial-stateless.jar"/>

   <!-- Build classpath -->
   <path id="classpath">
      <!-- So that we can get jndi.properties for InitialContext -->
      <pathelement location="${basedir}"/>
     <!-- Only the jbossall-client.jar should ideally be sufficient -->
      <fileset dir="${jboss.home}/client">
         <include name="**/jbossall-client.jar"/>
      </fileset>
     <!-- javax.persistence.* -->
      <fileset dir="${jboss.home}/server/default/lib">
           <include name="ejb3-persistence.jar"/>
           <include name="jboss-ejb3x.jar" />
           <include name="log4j.jar" />
         </fileset>
    
      <pathelement location="${build.classes.dir}"/>
   </path>

   <property name="build.classpath" refid="classpath"/>

 <!-- Override with your XDoclet bundle dist location -->
  <property name="xdoclet.home" value="E:/Program Files/java-sdk/xdoclet-1.2.3"/>
  <property name="xdoclet.lib" value="${xdoclet.home}/lib"/>

 
 <path id="xdoclet.path">
  <fileset dir="${xdoclet.lib}">
   <include name="*.jar"/>
  </fileset>
  <path refid="classpath"/>
 </path>
 
   <!-- =================================================================== -->
   <!-- Prepares the build directory                                        -->
   <!-- =================================================================== -->
   <target name="prepare">
      <mkdir dir="${build.dir}"/>
      <mkdir dir="${build.classes.dir}"/>
      <mkdir dir="${build.src.dir}"/>        
   </target>

   <!-- =================================================================== -->
   <!-- Compiles the source code                                            -->
   <!-- =================================================================== -->
   <target name="compile" depends="prepare,ejbdoclet">
      <javac
         destdir="${build.classes.dir}"
         debug="on"
         deprecation="on"
         optimize="off"
         includes="**">
         <classpath refid="classpath"/>
       <src path="${build.src.dir}" />
       <src path="${src.dir}" />
      </javac>
   </target>

   <!-- =================================================================== -->
     <!-- Invoke XDoclet's ejbdoclet                                          -->
     <!-- =================================================================== -->
     <target name="ejbdoclet" unless="xdoclet.skip">
         <taskdef
             name="ejbdoclet"
             classname="xdoclet.modules.ejb.EjbDocletTask"
             classpathref="xdoclet.path"
             />

         <ejbdoclet
             destdir="${build.src.dir}"
             excludedtags="@version,@author,@todo,@since"
             addedtags="@xdoclet-generated at ${TODAY},@copyright The XDoclet Team,@author XDoclet,@version ${version}"
             ejbspec="2.0"
             force="${xdoclet.force}"
             verbose="false"
             >

             <fileset dir="${src.dir}">
                 <include name="**/*Bean.java"/>
             </fileset>

             <packageSubstitution packages="bean" substituteWith="interfaces"/>

             <remoteinterface/>
             <localinterface/>
             <homeinterface/>
             <localhomeinterface/>

             <!--dataobject/-->
             <!--valueobject/-->

             <!--entitypk/-->

             <entitycmp/>
             <!--entitybmp/-->
             <session/>

             <!--dao>
                 <packageSubstitution packages="ejb" substituteWith="dao"/>
             </dao-->

             <!--utilobject cacheHomes="true" includeGUID="false"/-->

             <deploymentdescriptor
                destdir="${build.classes.dir}/META-INF"
                              validatexml="true"
                              description="stateless EJBs" >
                 </deploymentdescriptor>

           <jboss
                          version="4.0"
                          unauthenticatedPrincipal="nobody"
                          xmlencoding="UTF-8"
                          destdir="${build.classes.dir}/META-INF"
                          validatexml="true"
                                   
                          />
         
            
         </ejbdoclet>
     </target>
 
   <target name="ejbjar" depends="compile">
      <jar jarfile="build/${build.artifact}">
         <fileset dir="${build.classes.dir}">
            <include name="**/*.class"/>
          <include name="**/*.*" />
         </fileset>
      </jar>
      <copy file="build/${build.artifact}" todir="${jboss.home}/server/${jboss.server.config}/deploy"/>
   </target>

   <target name="run" depends="ejbjar">
      <java classname="org.jboss.tutorial.stateless.client.Client" fork="yes" dir=".">
         <classpath refid="classpath"/>
      </java>
   </target>

   <!-- =================================================================== -->
   <!-- Cleans up generated stuff                                           -->
   <!-- =================================================================== -->
   <target name="clean.db">
      <delete dir="${jboss.home}/server/${jboss.server.config}/data/hypersonic"/>
   </target>

   <target name="clean">
      <delete dir="${build.dir}"/>
      <delete file="${jboss.home}/server/${jboss.server.config}/deploy/${build.artifact}"/>
   </target>

 


</project>

 

 

(4)创建Client测试代码 -- Client.java

package org.jboss.tutorial.stateless.client;

import org.jboss.tutorial.stateless.interfaces.*;
import javax.rmi.*;

import javax.naming.InitialContext;

public class Client
{
   public static void main(String[] args) throws Exception
   {
   
      InitialContext ctx = new InitialContext();
      Object ref = ctx.lookup("CalculatorBean/re");
      CalculatorHome home = (CalculatorHome) PortableRemoteObject.narrow(ref,CalculatorHome.class);
      Calculator calculator = home.create();

      System.out.println("1 + 1 = " + calculator.add(1, 1));
      System.out.println("1 - 1 = " + calculator.subtract(1, 1));
      System.out.println("Hello Xdoclet");
   }
}

 

 

(5) 在eclipse里,右键选择build.xml,run as->ant build,就会自行进行编译和部署,会产生一个jboss-ejb3-tutorial-stateless.jar

文件,并被拷贝到"jboss安装目录/server/default/deploy"目录下

 

(6)双击"jboss安装目录/bin/run.bat",运行jboss。在提示信息中可以看到该ejb被加载。

 INFO  [EjbModule] Deploying Calculator
 INFO  [ProxyFactory] Bound EJB Home 'Calculator' to jndi 'CalculatorBean/re'

 

(7)配置jndi,进入到"项目目录/build/classes"目录,创建一个jndi.properties文件:

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost

 

(8)在"项目目录/build/classes"目录下,用命令行方式输入

    java -cp .;C:/jboss-4.2.3.GA/client/jbossall-client.jar org.jboss.tutorial.stateless.client.Client

 

1 + 1 = 2
1 - 1 = 0
Hello xdoclet

 

 

总结: Xdoclet主要就是简化你的开发工作,把EJB当中许多代码给你自动产生出来,这样特别有利于开发人员维护代码,减少无用的开发工作,把精力专注于业务逻辑中。

 

参考: http://xdoclet.sourceforge.net/xdoclet/index.html

        http://blog.csdn.net/omage/archive/2010/01/14/5191568.aspx

 

posted on 2010-01-17 18:23  omage  阅读(49)  评论(0编辑  收藏  举报