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符號 ' ' 單引號 " " 雙引號