paulwong

EJB Descriptor

  比如,我们有一个Bank(银行)类。Bank有两个方法,deposit(存钱)和withdraw(取钱)。
  
  类和方法的定义如下:
   网管有家www.bitscn.net
  Code 2.1 Bank.java
  class Bank{
  public float deposit(AccountInfo account, float money){
   // 增加account账户的钱数,返回账户里当前的钱数
  }
  
  public float withdraw(AccountInfo account, float money){
   // 减少account账户的钱数,返回取出的钱数
  }
  };
  
  这两个方法涉及到用户的账户资金等重要信息,必须要非常小心,所以编写完上面的商业逻辑之后,项目负责人又提出了新的要求--给Bank类的每个重要方法加上安全认证特性。
  
  于是,我们不得不分别在上面的两个方法中加入安全认证的代码。
  
  类和方法的定义如下:(新增加的代码用不同的背景标出)
  
  Code 2.2 Bank.java
  class Bank{
  public float deposit(AccountInfo account, float money){
   // 验证account是否为合法用户
   // 增加account账户的钱数,返回账户里当前的钱数
  }
  
  public float withdraw(AccountInfo account, float money){
   // 验证account是否为合法用户
   // 减少account账户的钱数,返回取出的钱数
  }
  }; 
  
  这两个方法都需要操作数据库,为了保持数据完整性,项目负责人又提出了新的要求--给Bank类的每个操作数据库的方法加上事务控制。
  
  于是,我们不得不分别在上面的两个方法中加入安全认证的代码。
  
  类和方法的定义如下:(新增加的代码用不同的背景标出)
  
  Code 2.3 Bank.java
  class Bank{
  public float deposit(AccountInfo account, float money){
   // 验证account是否为合法用户
   // Begin Transaction
   // 增加account账户的钱数,返回账户里当前的钱数
   // End Transaction
  }
  
  public float withdraw(AccountInfo account, float money){
   // 验证account是否为合法用户
   // Begin Transaction
   // 减少account账户的钱数,返回取出的钱数
   // End Transaction
  }
  };
  
  我们看到,这些与商业逻辑无关的重复代码遍布在整个程序中。实际的工程项目中涉及到的类和函数,远远不止两个。如何解决这种问题?
  
  我们首先来看看OOP能否解决这个问题。
  
  我们利用Design Pattern的Template Pattern,可以抽出一个框架,改变上面的例子的整个设计结构。


  
  类和方法的定义如下:
  
  Code 2.4 Base.java
  abstract class Base{
  public float importantMethod(AccountInfo account, float money){
   // 验证account是否为合法用户
   // Begin Transaction
   
   float result = yourBusiness(account, money)
  
   // End Transaction
   return result;
  }
  
  protected abstract float yourBusiness(AccountInfo account, float money);
  };
  
  Code 2.5 BankDeposit.java
  class BankDeposit extends Base{
  protected float yourBusiness(AccountInfo account, float money){
   // 增加account账户的钱数,返回账户里当前的钱数
  }
  };
  
  Code 2.6 BankWithdraw.java
  class BankWithdraw extends Base{
  protected float yourBusiness(AccountInfo account, float money){
   // 减少account账户的钱数,返回取出的钱数
  }
  };
  
  这里我们用一种很勉强的方法实现了认证和事务代码的重用。而且,有心的读者可能会注意到,这种方法的前提是,强制所有的方法都遵守同样的signature。


  
  如果有一个转账方法transfer(AccountInfo giver, AccountInfo receiver, float money),由于transfer方法的signature不同于yourBusiness的signature,这个方法无法使用上面的框架。
  
  这个例子中提到的认证,事务等方面,就是AOP所关心的Aspect。
  
  AOP就是为了解决这种问题而出现的。AOP的目的就是--Separation of Aspects (or Separation of Concerns).
  
  下面的章节,解释EJB Descriptor,AspectJ,xDoclet等工具如何解决Separation of Aspects的问题。
  
  3.EJB Descriptor
  如果我们使用EJB实现上面的例子,Bank类可以作为一个Stateless Session Bean实现。
  
  在Bank的代码中只用考虑商业逻辑,不用考虑认证和事务等方面。
  
  认证和事务等方面在EJB Descriptor中定义,由EJB Container提供这些方面的实现。
  
  我们来看一下,如何使用EJB Descriptor描述上面的例子。
  
  EJB Descriptor包括一个ejb-jar.xml文件。ejb-jar.xml文件包含两大部分,enterprise-beans和assembly-descriptor部分。enterprise-beans部分包含EJB的定义--JNDI Name,EJB Home, Interface, Bean Class Path等;assembly-descriptor部分包括配置信息的定义--安全角色,事务控制等等。 
  
  下面给出上面例子对应的模拟EJB Descriptor。
  
  <ejb-jar>
  <enterprise-beans>
   <session>
     <ejb-name>Bank</ejb-name>
     …
     <ejb-class>example.Bank</ejb-class>
     <session-type>Stateless</session-type>
     <transaction-type>Container</transaction-type>
  <security-role-ref>
  <role-name>bank-account</role-name>
  </security-role-ref>
   </session>
  </enterprise-beans>
  
  <assembly-descriptor>
   <security-role>
    <role-name>bank-account</role-name>
   </security-role>
  
  <method-permission>
  <role-name>employee</role-name>
  <method>
  <ejb-name>Bank</ejb-name>
  <method-name>deposit</method-name>
  </method>
  <method>
  <ejb-name>Bank</ejb-name>
  <method-name>withdraw</method-name>
  </method>
  </method-permission> 
  
  <container-transaction>
  <method>
  <ejb-name>Bank</ejb-name>
  <method-name>deposit</method-name>
  </method>
  <method>
  <ejb-name>Bank</ejb-name>
  <method-name>withdraw</method-name>
  </method>
  
  <trans-attribute>Required</trans-attribute>
  </container-transaction>
  </assembly-descriptor>
  </ejb-jar>


  定義部署描述檔


    此篇文章適合的讀者以及內容

此篇文章適合的讀者為Enterprise Bean提供者,例如,負責開發伺服器端的軟體 元件者。此篇文章描述Enterprise Bean提供者應該如何為他所寫的元件撰寫所需 的部署描述檔。

此篇文章包含以下的內容:
1. 此篇文章適合的讀者以及內容 <#Target>
2. 原則 <#Princip>
3. Session Bean描述檔範例 <#Exampl1>
4. Container-managed Persistence(CMP) Entity Bean描述檔範例 <#Exampl2>
5. 使用技巧 <#Tips>
原則

Enterprise bean的程式設計師負責提供所開發的Enterprise Bean所關聯的部署描 述檔。隨著Enterprise JavaBean應用程式開發與部署的生命週期的不同階段(開 發,彙合,部署),部署描述檔必須要被完成。


Enterprise Bean提供者跟應用程式集合者的責任是提供XML部署描述檔,並符合 EJB 2.0規格裡所定義的XML部署檔的DTD。(詳見|$JONAS_ROOT/xml/ejb- jar_2_0.dtd|)。


在EJB伺服器上部署Enterprise JavaBean時,可能還需要一些沒有定義在標準的 XML部署描述檔裡面的資訊。這些資訊包括如CMP Entity Bean所使用的資料庫的對 應資訊等。在部署階段的時候,這資訊是被指定的,另外在JOnAS特定的XML部署描 述檔裡。JOnAS特定的部署描述檔的XML DTD可以在|$JONAS_ROOT/xml/jonas-ejb- jar_X_Y.dtd|被找到。這個JOnAS特定的XML部署描述檔的名稱必須是用標準的XML 部署描述檔名前再加'jonas-'。

在XML解析器去解析部署描述檔時,JOnAS對標籤做了特別的解釋。

首先解析器會先試著去取得classpath裡指定的DTD檔案,然後才是透過指定的URL 或路徑去取得。


範例:如下的兩個範例,XML解析器取得於JOnAS jar檔案裡的|jonas-ejb- jar_2_4.dtd|DTD檔案:

    <!DOCTYPE jonas-ejb-jar PUBLIC "-//ObjectWeb//DTD JOnAS 2.4//EN"
"http://www.objectweb.org/jonas/dtds/jonas-ejb-jar_2_4.dtd";>
<!DOCTYPE jonas-ejb-jar SYSTEM
"/usr/local/jonas/xml/jonas-ejb-jar_2_4.dtd">

標準的部署描述檔應該包含每個Enterprise Beas結構的資訊如下:
* Enterprise bean的名稱,
* Enterprise bean的類別,
* Enterprise bean的Home介面,
* Enterprise bean的Remote介面,
* Enterprise bean的型別,
* 重新加入Entity bean的指示,
* Session bean的狀態管理型態,
* Session bean的Transaction分界型態,
* Entity bean的Persistence管理,
* Entity bean的主鍵類別,
* Container管理的欄位,
* 環境項目,
* Bean的EJB參考,
* 資源管理員連線Factory參考,
* Transaction的屬性。
JOnAS特定的部署描述檔包含每個Enterprise Bean的資訊如下:
* 實作Enterprise Bean中Home介面的Home物件之JNDI名稱,
* 在Enterprise Beas類別中所參考到的資源管理員連線Factory,其所對應的
DataSource物件的JNDI名稱,
* 每個EJB參考的JNDI名稱,
* JMS管理物件的JNDI名稱,
* CMP Entity Bean所使用的資源庫的對應資訊。
Session Bean部署描述檔範例
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
"http://java.sun.com/dtd/ejb-jar_2_0.dtd";>
<ejb-jar>
<description>Here is the description of the test's beans</description>
<enterprise-beans>
<session>
<description>... Bean example one ...</description>
<display-name>Bean example one</display-name>
<ejb-name>ExampleOne</ejb-name>
<home>tests.Ex1Home</home>
<remote>tests.Ex1</remote>
<ejb-class>tests.Ex1Bean</ejb-class>
<session-type>Stateful</session-type>
<transaction-type>Container</transaction-type>
<env-entry>
<env-entry-name>name1</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>value1</env-entry-value>
</env-entry>
<ejb-ref>
<ejb-ref-name>ejb/ses1</ejb-ref-name>
<ejb-ref-type>session</ejb-ref-type>
<home>tests.SS1Home</home>
<remote>tests.SS1</remote>
</ejb-ref>
<resource-ref>
<res-ref-name>jdbc/mydb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Application</res-auth>
</resource-ref>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>ExampleOne</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>ExampleOne</ejb-name>
<method-inter>Home</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Supports</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>ExampleOne</ejb-name>
<method-name>methodOne</method-name>
</method>
<trans-attribute>NotSupported</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>ExampleOne</ejb-name>
<method-name>methodTwo</method-name>
<method-params><method-param>int</method-param></method-params>
</method>
<trans-attribute>Mandatory</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>ExampleOne</ejb-name>
<method-name>methodTwo</method-name>
<method-params><method-param>java.lang.String</method-param></method-params>
</method>
<trans-attribute>NotSupported</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
<!DOCTYPE jonas-ejb-jar PUBLIC "-//ObjectWeb//DTD JOnAS 2.4//EN"
"http://www.objectweb.org/jonas/dtds/jonas-ejb-jar_2_4.dtd";>
<jonas-ejb-jar>
<jonas-session>
<ejb-name>ExampleOne</ejb-name>
<jndi-name>ExampleOneHome</jndi-name>
<jonas-ejb-ref>
<ejb-ref-name>ejb/ses1</ejb-ref-name>
<jndi-name>SS1Home_one</jndi-name>
</jonas-ejb-ref>
<jonas-resource>
<res-ref-name>jdbc/mydb</res-ref-name>
<jndi-name>jdbc_1</jndi-name>
</jonas-resource>
</jonas-session>
</jonas-ejb-jar>

    Container-managed Persistence Entity Bean描述檔範例(CMP 1.1)
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
"http://java.sun.com/dtd/ejb-jar_2_0.dtd";>
<ejb-jar>
<description>Here is the description of the test's beans</description>
<enterprise-beans>
<entity>
<description>... Bean example one ...</description>
<display-name>Bean example two</display-name>
<ejb-name>ExampleTwo</ejb-name>
<home>tests.Ex2Home</home>
<remote>tests.Ex2</remote>
<ejb-class>tests.Ex2Bean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>tests.Ex2PK</prim-key-class>
<reentrant>False</reentrant>
<cmp-version>1.x</cmp-version>
<cmp-field>
<field-name>field1</field-name>
</cmp-field>
<cmp-field>
<field-name>field2</field-name>
</cmp-field>
<cmp-field>
<field-name>field3</field-name>
</cmp-field>
<primkey-field>field3</primkey-field>
<env-entry>
<env-entry-name>name1</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>value1</env-entry-value>
</env-entry>
</entity>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>ExampleTwo</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Supports</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
<!DOCTYPE jonas-ejb-jar PUBLIC "-//ObjectWeb//DTD JOnAS 2.4//EN"
"http://www.objectweb.org/jonas/dtds/jonas-ejb-jar_2_4.dtd";>
<jonas-ejb-jar>
<jonas-entity>
<ejb-name>ExampleTwo</ejb-name>
<jndi-name>ExampleTwoHome</jndi-name>
<jdbc-mapping>
<jndi-name>jdbc_1</jndi-name>
<jdbc-table-name>YourTable</jdbc-table-name>
<cmp-field-jdbc-mapping>
<field-name>field1</field-name>
<jdbc-field-name>dbf1</jdbc-field-name>
</cmp-field-jdbc-mapping>
<cmp-field-jdbc-mapping>
<field-name>field2</field-name>
<jdbc-field-name>dbf2</jdbc-field-name>
</cmp-field-jdbc-mapping>
<cmp-field-jdbc-mapping>
<field-name>field3</field-name>
<jdbc-field-name>dbf3</jdbc-field-name>
</cmp-field-jdbc-mapping>
<finder-method-jdbc-mapping>
<jonas-method>
<method-name>findByField1</method-name>
</jonas-method>
<jdbc-where-clause>where dbf1 = ?</jdbc-where-clause>
</finder-method-jdbc-mapping>
</jdbc-mapping>
</jonas-entity>
</jonas-ejb-jar>

    使用技巧
有一些字元,如"<"和"&"在XML資料裡嚴格來說是不合法的。
其他像">"則是合法的,但習慣上最好將這些字元置換成XML的實體對應。
以下列示出XML裡事先定義好的實體對應:
&lt;        <    小於
&gt;        >    大於
&amp;       &   And符號
&apos;      '       單引號
&quot;      "  雙引號

posted on 2008-12-06 16:29 paulwong 阅读(200) 评论(0)  编辑  收藏 所属分类: J2EE


只有注册用户登录后才能发表评论。


网站导航: