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裡事先定義好的實體對應: < < 小於 > > 大於 & & And符號 ' ' 單引號 " " 雙引號
posted on 2008-12-06 16:29 paulwong 閱讀(202) 評論(0) 編輯 收藏 所屬分類: J2EE