資料和服務 – 通向企業服務匯流排(ESB)之路
在前面的章節中,我們已經學習了XML的基礎知識以及基於XML的Web服務。現在,我們就可以從企業級的視角,看看這些是如何組裝起來。對企業使用者來說,資訊及資訊的基本構成元素—資料是他們所感興趣的。資料可以駐留在任何資料儲存中心,並以各種形式存在。如果不考慮資料儲存和格式,您需要將資料存到表中,並應用企業業務邏輯對它們進行處理,然後它們才能變為資訊提供給使用者。那麼,在SOA世界,我們怎樣才能從傳統的JDBC或ORM(Object-relations mapping, 資料關係對映)中解脫出來?而且,更加另我們感興趣的是,資料甚至可以以服務的形式存在,如果是這樣,我們怎樣將多個服務組合起來,並對它們進行查詢,就象我們將多個
JDO作為替代JDBC的可選方案;
資料服務及其在SOA中的角色;
即將出現的資料服務標準,例如SCA和SDO;
對Apache Tuscany進行介紹;
介紹MOM(message-oriented middleware,訊息中介軟體);
企業服務匯流排ESB(Enterprise Service Bus)—一種全新的架構體系
介紹OpenESB
JDO簡介
您對JDBC及ORM框架(如Hibernate和Toplink)已駕輕就熟,但現在我們卻要介紹Java另外一種資料訪問形式 – JDO(Java Data Object
為什麼要使用JDO?
我們都有使用JDBC從關係資料庫中提取資料的程式設計經驗。但現在的問題是,我們是否需要另一種標準 – JDO來訪問資料?作為一名軟體開發者,如果您認為您需要對您的業務問題提供解決方案,您會從業務用例開始
分離關注點:使用JDO,應用開發者可以專注於業務領域物件模型(BDOM),而將那些資料持久化的細節(如資料的儲存及提取)留給JDO;
JDO是基於介面的:JDO是一種基於Java介面的程式設計模型,因此,所有的持久化行為,如ORM框架中的一些最常用的功能,是以元資料(metadata)的形式存在,元資料獨立於您的BDOM原始碼;另外,您也可以以即插即用(Plug and Play, PNP)的方式使用多種JDO實現。
資料儲存方式的可移動性:持久化儲存方式不管是關係型的,還是基於物件,或者只是一個XML資料庫或扁平檔案,JDO的實現都能支援它們。因此,基於JDO的應用是獨立於底層資料庫的。
效能:JDO知道如何更好地同資料儲存中心進行互動,同開發者編寫的程式碼相比,這可以提高資料訪問的效能。
和J2EE的整合:JDO應用可以利用J2EE的一些特點,如EJB及遠端訊息處理、自動分散式交易的協作、安全等這些J2EE企業級特色。
JPOX—Java持久化物件
JPOX是Apache的一個開源專案,它使用JDO,為Java訪問異種資料來源提供了一種解決方案。我們這裡指的JPOX JDO支援的異種資料來源,主要包括下列持久化方案四個主要方面特色的各種組合:持久化定義:它定義瞭如何將您的BDOM類持久化到資料儲存中;
持久化API:用來持久化您的BDOM物件的API程式設計介面;
查詢語言:按照特定的條件來查詢物件的一種語言;
資料儲存:儲存您的物件的底層資料儲存中心。
使用JPOX的JDO示例
在本例中,我們將使用我們熟悉的訂單(Order)和商品(LineItems),將它們擴充套件到JDO實現。假定您已下載並把JPOX庫解壓到您的本地硬碟。
本例中的BDOM(業務域物件模型)
為方便討論,我們這裡只考慮兩個實體類,即OrderList(訂單列表)和LineItem(單個商品),這兩個類的屬性及它們的關係如下圖所示:
上面的BDOM表明,一個訂單可以包含多個商品,而一個商品屬於且僅屬於一個訂單。
JDO中的BDOM實體類原始碼
BDOM中的實體類非常簡單,只為每個屬性提供了getter和setter方法。接下來,這些類需要通過JDO的配置檔案連線到JDO,從而可以利用JDO的持久化的能力,但這些完全獨立於核心的實體類。
OrderList.java
OrderList類代表訂單(Order),它有一個主鍵屬性number:
public class OrderList{
private int number;
private Date orderDate;
private Set lineItems;
// other getter & setter methods go here
// Inner class for composite PK
public static class Oid implements Serializable{
public int number;
public Oid(){
}
public Oid(int param){
this.number = param;
}
public String toString(){
return String.valueOf(number);
}
public int hashCode(){
return number;
}
public boolean equals(Object other){
if (other != null && (other instanceof Oid)){
Oid k = (Oid)other;
return k.number == this.number;
}
return false;
}
}
}
LineItem.java
LineItem代表訂單中包含的每個商品,雖然JDO中可以為LineItem定義主鍵,但這裡我們並沒有為它顯示地定義主鍵。
public class LineItem{
private String productId;
private int numberOfItems;
private OrderList orderList;
// other getter & setter methods go here
}
package.jdo
JDO需要一個XML配置檔案,來定義要持久化的資料列,以及這些列使用何種JDBC或JDO進行封裝對映。為此,我們可以建立一個名為package.jdo的XML檔案,其內容如下,並把它放到和JDO實體類相同的目錄中。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jdo SYSTEM "file:/javax/jdo/jdo.dtd">
<jdo>
<package name="com.binildas.jdo.jpox.order">
<class name="OrderList" identity-type="application"
objectid-class="OrderList$Oid" table="ORDERLIST">
<field name="number" primary-key="true">
<column name="ORDERLIST_ID"/>
</field>
<field name="orderDate">
<column name="ORDER_DATE"/>
</field>
<field name="lineItems" persistence-modifier="persistent"
mapped-by="orderList">
<collection element-type="LineItem">
</collection>
</field>
</class>
<class name="LineItem" table="LINEITEM">
<field name="productId">
<column name="PRODUCT_ID"/>
</field>
<field name="numberOfItems">
<column name="NUMBER_OF_ITEMS"/>
</field>
<field name="orderList" persistence-modifier="persistent">
<column name="LINEITEM_ORDERLIST_ID"/>
</field>
</class>
</package>
</jdo>
jpox.PROPERTIES
本例中,我們將把我們的實體類持久化到關係資料庫Oracle中,我們需要在jpox.PROPERTIES檔案中指定主要的資料庫連線引數:
javax.jdo.PersistenceManagerFactoryClass=org.jpox.jdo.JDOPersistenceManagerFactory
javax.jdo.option.ConnectionDriverName=oracle.jdbc.driver.OracleDriver
javax.jdo.option.ConnectionURL=jdbc:oracle:thin:@127.0.0.1:1521:orcl
javax.jdo.option.ConnectionUserName=scott
javax.jdo.option.ConnectionPassword=tiger
org.jpox.autoCreateSchema=true
org.jpox.validateTables=false
org.jpox.validateConstraints=false
Main.java
這個類用來測試JDO的功能,其程式碼如下,它首先建立兩個訂單(Order)物件,然後為每個訂單新增幾個商品,然後它持久化這些實體類物件,並通過id屬性來查詢返回這些實體化物件。
public class Main{
static public void main(String[] args){
Properties props = new Properties();
try{
props.load(new FileInputStream("jpox.properties"));
}
catch (Exception e){
e.printStackTrace();
}
PersistenceManagerFactory pmf =
JDOHelper.getPersistenceManagerFactory(props);
PersistenceManager pm = pmf.getPersistenceManager();
Transaction tx = pm.currentTransaction();
Object id = null;
try{
tx.begin();
LineItem lineItem1 = new LineItem("CD011", 1);
LineItem lineItem2 = new LineItem("CD022", 2);
OrderList orderList = new OrderList(1, new Date());
orderList.getLineItems().add(lineItem1);
orderList.getLineItems().add(lineItem2);
LineItem lineItem3 = new LineItem("CD033", 3);
LineItem lineItem4 = new LineItem("CD044", 4);
OrderList orderList2 = new OrderList(2, new Date());
orderList2.getLineItems().add(lineItem3);
orderList2.getLineItems().add(lineItem4);
pm.makePersistent(orderList);
id = pm.getObjectId(orderList);
System.out.println("Persisted id : "+ id);
pm.makePersistent(orderList2);
id = pm.getObjectId(orderList2);
System.out.println("Persisted id : "+ id);
orderList = (OrderList) pm.getObjectById(id);
System.out.println("Retreived orderList : " + orderList);
tx.commit();
}
catch (Exception e){
e.printStackTrace();
if (tx.isActive()){
tx.rollback();
}
}
finally{
pm.close();
}
}
}
編譯並執行JDO例項程式
首先,如果您沒有修改過本章下載程式碼中的examples.PROPERTIES檔案,請編輯該檔案,將其中的目錄路徑指向您的開發環境。在您下載的本章程式碼中,也包含一個README.txt檔案,它也說明了編譯和執行本例的詳細步驟。因為我們使用Oracle來持久化實體類,我們還需要把下面兩個庫檔案加到classpath中:
jpox-rdbms*.jar
classes12.jar
我們還需要其它一些庫檔案,您可以在build.xml檔案中找到它們,請下載這些jar檔案,並相應地修改examples.PROPERTIES配置檔案中的路徑。要編譯本例,首先啟動您的資料庫伺服器,然後鍵入ant命令編譯編譯它,您可以進到本書原始碼的ch04/jdo目錄,並執行下面的命令:
cd ch04/jdo
ant
上面的命令將執行下列步驟:
首先,它編譯Java原始碼;然後JPOX庫對每個持久化類的位元組碼進行增強;
然後,它將在資料庫中建立所需的資料庫模式(表的定義)。
要執行本例,請執行下面的ant命令:
ant run
您現在可以交叉檢查您的實體類是否儲存(持久化)到資料庫,下圖顯示了Oracle資料庫中的訂單及其子元素商品資料。