paulwong

#

Session Bean

1. 簡介

Session Bean 是目前 EJB 規格 (EJB 2.0) 中 3種 Enterprise Bean 的其中一種,另外兩種分別是 Entity Bean 和 Message Driven Bean,這3種 Enterprise Bean 依照其特性被應用在不同的範疇中。其中 Session Bean 和 Entity Bean 早在 EJB 1.x 規格中就已經存在,Message Driven Bean 卻是在 EJB 2.0 才被加入。

在 EJB 架構中,Session Bean 主要目的是塑造企業流程,當中可能包括系統運算、存取資料庫、呼叫其他 Enterprise Bean等等。其範例包括流程引擎、買賣交易、型錄查詢等應用。接下來會從 Session Bean 的各個不同的特性說明其實際應用的方式、時機和要注意的地方。

2. Stateless & Stateful Session Bean

EJB 規格中,Session Bean被細分為 Stateless Session Bean Stateful Session Bean。兩者根據特性在應用上有著很大差異:

與客戶端之間的對話資訊

Session Bean 不能被共用,每一個 Bean 只能用來服務一個客戶,而 Bean 和客戶端之間會有一份對話資訊 (請參考附註 [A] )

●Stateless Session Bean

基本上只在單一方法呼叫中保存對話資訊,一旦 Bean 完成處理後,對話資訊會隨著被清除。

●Stateful Session Bean

在同一個 Session 可以保留呼叫者與 Session Bean 之間的對話資訊與狀態,等下一次執行方法時繼續提供使用。

生命週期

Session Bean 的生命週期除了依不同廠商的 EJB Container 會有所不同外,Bean 的 Stateful 特性也會影響到其存活的時機。

●Stateless Session Bean

當客戶端所呼叫 Stateless Session Bean完畢後,Bean 會馬上被 EJB Container 銷毀,或將實例 (Instance) 保存下來以供其他客戶端使用。

●Stateful Session Bean

和 Stateless Session Bean 不同,當客戶端所呼叫Stateless Session Bean完畢後,Bean 不會馬上被 EJB Container 銷毀,而是繼續存在於 Session Bean Pool (請參考附註 [B] ),直到 Session 完結。

使用時機

●Stateless Session Bean

1. 不需要在每次客戶端對 Session Bean 的方法呼叫後保持對話資訊。

●Stateful Session Bean

1. 在每個 Session Bean 的方法呼叫之間需要保持 Session 中的資訊。

2. 利用 Session Bean 的對話狀態 (Conversational State) (請參考附錄) 管理企業流程

效能

●Stateless Session Bean

由於不需要管理對話資訊,也就是可以佔用比較少系統資源去暫存與客戶端之間的對話資訊,而且在每次被呼叫完畢後可以馬上轉移給其他客戶端使用,故效能較佳。

●Stateful Session Bean

每次被客戶端呼叫完畢後都會將代表這客戶端的狀態資訊暫時儲存起來,在 Session 完畢後也要把之前所記錄與客戶端的對話資訊清除,所以會消耗較多系統資源。

3. 開發 Session Bean

開發一支 Session Bean 至少包括4個步驟

1. 編寫 Home Interface

2. 編寫 Remote Interface

3. 編寫 Bean 的實作 (Implement) 類別,當中包括描述企業流程的方法實作

4. 編寫部署文件 (ejb-jar.xml)

編寫 Home 介面

Session Bean 的`介面繼承自 javax.ejb.EJBHome,負責控制一個 Session Bean 的生命週期,含有建立與銷毀 EJB 物件的方法,一般情況下,其命名規則為 <<Bean-name>> + Home。要注意的是,Home介面中需要定義一個 create() 方法 (對應到 Bean 實作類別的 ejbCreate()),用來取得一個 Bean 的實例。另外 Home 介面中也可以定義一個 remove() 方法對應到 Bean 實作類別的 ejbRemove()),用來移除 Bean 的實例。

【範例】

package examples;

import javax.ejb.*;

import java.rmi.RemoteException;

public Interface HelloWorldHome extends EJBHome{

HelloWorld create() throws RemoteExcception, CreateException;

}

編寫 Remote介面

繼承自 javax.ejb.EJBObject,含有 Bean 裡所有的每一個方法以供遠端程序呼叫,一段情況下,其命名規則為 <<Bean-name>>。由於遠端介面是 RMI-IIOP 遠端介面 (繼承 java.rmi.Remote) ,因此必須拋出 java.rmi.RemoteException。

【範例】

package examples;

import javax.ejb.*;

import java.rmi.RemoteException;

public Interface HelloWorld extends EJBObject{

public void helloWorld() throws RemoteException;

}

編寫 Session Bean 的實作類別

繼承自 javax.ejb.SessionBean,一段情況下,其命名規則為 <<Bean-name>> + Bean。定義一個 Session Bean 可以透過定義一個實現 javax.ejb.SessionBean 介面的類別來達成,該介面定義如下:

public Interface javax.ejb.SessionBean extends javax.ejb.EnterpriseBean{

public void ejbCreate(…) throws RemoteException;

public void ejbActivate() throws RemoteException;

public void ejbPassivate() throws RemoteException;

public void ejbRemove() throws RemoteException;

public void setSessionContext(SessionContext ctx) throws RemoteException;

}

以上幾個方法並不是要讓客戶端使用和呼叫的,而是要讓 EJB Container 使用來管理 Session Bean 的生命週期,因此不可以直接在客戶端程式裡呼叫。每個方法的說明如下,詳細的方法呼叫時機請參考「Session Bean 與 EJB Container 互動」:

方法

說明

ejbCreate(…)

初始化 Session Bean

ejbActivate()

EJB container Session Bean 主動化 (activate) 後馬上呼叫此一方法,取得 Bean 所需資源 ( stateless 不需實作,因為不需維護對話資訊)

ejbPassivate()

EJB container Session Bean 被動化 (passivate) 後馬上呼叫此一方法,釋放 Bean 所佔的資源( socket 連線)

ejbRemove()

EJB container Session Bean 從記憶體中移除之前會呼叫此一方法,釋放所有已配置的資源

setSessionContext(SessionContext ctx)

EJB container Session Bean Session Context 關聯在一起,Bean 可以從中查詢目前交易狀態和資訊

【範例】

package examples;

import javax.ejb.*;

public Interface HelloWorldBean extends EJBObject{

public void helloWorld(){

         System.out.println(“Hello Word !!!”);

}

public void ejbCreate() throws CreateException{

       System.out.println(“ejbCreate”);

}

public void ejbRemove() {

       System.out.println(“ejbRemove”);

}

public void ejbActivate() {

       System.out.println(“ejbActivate”);

}

public void ejbPassivate() {

       System.out.println(“ejbPassivate”);

}

public void setSessionContext(SessionContext ctx) {

       System.out.println(“setSessionContext”);

}

}

編寫部署文件 ejb-jar.xml

要讓所編寫的 Session Bean 可以在 EJB Container 部署和正確運作,除了編寫程式碼外,我們還需要把 Session Bean 的特性描述在部署文件,也就是 ejb-jar.xml。編寫 Session Bean 不需要在程式碼中指明所寫的 Bean stateless 還是 stateful,其 stateful 特性是定義在部署文件裡,也就是說可以透過修改部署文件而簡單的把 Session Bean 在 stateless 和 stateful 之間切換。

【範例】

<!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>

<enterprise-Beans>

         <Session>

                 <ejb-name>Hello</ejb-name>

                 <Home>examples.HelloWorldHome</Home>

                 <remote>examples.HelloWorld</ remote>

                 <ejb-class>examples.HelloWorldBean</ejb-class>

                 <Session-type>Stateless</Session-type>

                 <transaction-type>Container</transaction-type>

         </Session>

</enterprise-Beans>

</ejb-jar>

<ejb-name>

Session Bean 的名稱

<Home>

Session Bean Home 介面

<remote>

Session Bean remote 介面

<ejb-class>

Session Bean 實作的類別

<Session-type>

描述Session Bean stateful 特性 (Stateless / Stateful)

<transaction-type>

描述 Session Bean 的交易特性 (Container / Bean)

4. Session Bean EJB Container 互動

在客戶端的程式呼叫 Session Bean 的方法時,其實 Bean 會根據其特性 (stateful 特性) 和 EJB container 互動,以下簡單的說明 EJB container 如何管理 Session Bean 的生命週期。

Stateless Session Bean

1.     當客戶端程式呼叫 Stateless Session Bean 上的方法之前,會先呼叫 Bean 的Home 介面中的create() 以取得一個 Bean 的參考 (reference)。

2.      EJB container 會馬上呼叫 ejbCreate() 和 setSessionContext() 產生一個 Bean 實例和把 Session Context 和 Bean 關聯在一起。

3.     當方法呼叫完畢,EJB container 會呼叫 ejbRemove() 把 Bean 銷毀,Bean 所佔用的資源也會被釋放。

Stateful Session Bean

1.      Stateless Session Bean 一樣客戶端程式呼叫 Stateful Session Bean 上的方法之前會先呼叫 create() 取得一個 Bean 的參考。

2.     EJB container 會馬上呼叫 ejbCreate() 和 setSessionContext() 產生一個 Bean 實例和把 Session Context 和 Bean 關聯在一起。

3.     由於 Stateful Session Bean 會管理與客戶端之間的對話資訊,所以在Bean 的方法被呼叫完畢後,EJB container 不會馬上把 Bean 銷毀,而是在適當時間 (依不同廠商的EJB Container 會有所不同) 把 Bean 被動化 (呼叫 ejbPassivate()) 和將對話資訊暫存起來。

4.     當客戶端程式再次呼叫 Bean 上的方法時,如果 Bean 是在被動狀態,EJB container 會呼叫 Bean 的 ejbActivate() 把 Bean 的狀態轉為預備狀態,而之前暫存的對話資訊也會再放進 Bean 實例裡。

5.     客戶端程式呼叫 Bean remove() 或是客戶端的 Session 已經完結時,EJB container會呼叫 ejbRemove() 把 Bean 銷毀,Bean 所佔用的資源也會被釋放,之前所保持的與客戶端之間的對話資訊也會同時被清除。



附註 [A] 對話資訊:包括 Session 資訊和對話狀態 Conversational State。當客戶端程式呼叫 Session Bean 時,可能會改變其實例參數 (Instance Variable) 的值。在客戶端程式再次呼叫同一個 Session Bean 參考的方法時,Stateful Session Bean 會保留上次方法呼叫被改變的實例參數的值,但 Stateless Session Bean 卻不會。

附註 [B] Session Bean Pool:EJB container 存放 Session Bean 實例 (Instance) 的地方,可根據不同的需要而設定大小 (設定於佈署文件中),Pool 的大小會影響系統效能。

posted @ 2008-12-04 11:32 paulwong 阅读(529) | 评论 (0)编辑 收藏

Entity Bean(2)

     摘要: 四、Entity bean的實作   在上一節我們簡略地介紹了entity bean的生命週期的各種狀態與相關的life-cycle與call back方法,在本節中我們則要以實際的程式碼說明CMP與BMP在實作這些life-cycle與call back方法時的異同與值得注意之處。但無論是CMP bean或BMP bean,開發人員都必須提供下列檔案: 1. &nb...  阅读全文

posted @ 2008-12-04 11:32 paulwong 阅读(484) | 评论 (0)编辑 收藏

Entity Bean(1)

一、前言

從前面幾期的介紹,我們知道Enterprise JavaBean(EJB)J2EE架構中用來實作business tier的技術。就J2EE Design Pattern而言,business tier代表了MVC pattern中的modelmodel負責處理的是對business最重要的domain objectsbusiness logic。在這個脈絡下,J2EE Design Pattern建議我們使用session beanmessage-driven bean實作business logic,而以entity bean實作domain objects。透過使用entity bean,我們以物件模式塑模(modeling)business data,這不僅使我們可以運用物件導向程式設計的優點,也得以享受EJB Container提供的各種背景服務(PersistenceTransactionSecurityConcurrency)。本期及下一期我們將就entity bean的種類、生命週期、程式碼的實作、以及client端的使用對entity bean做一初步的介紹。後續的幾期我們將介紹entity bean的進階功能與相關設定。

二、Entity bean的種類

就資料保存(Data Persistency)的觀點而言,entity bean以物件模式保存資料只是各種資料保存模式中的一種。在實作中,entity bean除了接收來自clent端的資料外,主要還是從所謂的Enterprise Information System tier(EIS)取得既存的資料並將處理後的資料儲存在EIS tier,而關聯式資料庫(RDBM)則是目前最為普遍的EIS tier技術。面對不同的資料保存模式,如何在不同的tier之間維持資料的一致性與完整性(Data Interity)是個重要的課題。針對這個問題,EJB提供了兩種技術:CMP beanBMP beanBMP bean(Bean-Managed Persistence)將有關資料保存的工作交由開發人員負責,開發人員必須熟悉EJB Container呼叫call back 方法與其他bean life-cycle方法的時機與方式,並在BMP bean中實作與存取資料庫有關的程式碼。而CMP bean(Container-Managed Persistence)則將有關資料保存的工作交由EJB Container處理,開發人員不需要在entity bean中編寫有關存取資料庫的程式碼,而只需要在部署描述子(deployment descriptor)中定義好entity bean與資料庫之間的對應(mappings),在部署階段部署工具會自動產生相關的JDBC程式碼。這麼做的好處首先在於實際部署時得以動態產生entity beandata sources之間的繫結;更重要的是,它使開發人員得以專注於以物件導向的思維模式集中心力於business logic上。

EJB 1.1規格書中並沒有對CMP如何與資料庫schema之間的mappings提出一個標準的規範,此外對於如何建立多個entity bean之間的關係,如何尋找與定位(finding and locating)entity bean的做法亦付之闕如。但在EJB 2.0規格書中則對CMP做出了重大的改進,包括標準的Query Language(QL)Container-Managed Relationships(CMR)等,我們將在下期作進一步的介紹。以下是有助於選擇CMPBMP的因素:

1.       CMPBMP易於開發維護,EJB Container會對資料存取的過程做最佳化。

2.       BMP適用於對效能要求較高與較為複雜的應用程式,但若開發不當,則很容易拖垮系統的效能。

3.       CMP不支援較為複雜的SQL語法,如在where子句中對日期與時間的比較。

4.       CMP支援的data sources類型受container provider的限制。此外目前的CMP並不支援非JDBCdata sources

5.       如果要使用CMR,則必須使用CMP

三、Entity bean的生命週期

EJB Container運用集區(Pool)的概念來管理entity bean以妥善運用系統資源並增進系統效能。根據entity bean是否被放入集區與是否與EJB Object結合,entity bean有三種狀態:分別是Not Exist StatePooled StateReady State。下圖展示了EJB Container如何藉由呼叫bean classcall backlife-cycle方法在這三種狀態間轉換(下圖引用自Richard Monson-Haefel, Enterprise JavaBeans, 3rd Edition, O’Reilly,Page 308, Figure 11-2)

1.       Not Exist State

在這個狀態中,entity bean可視為一堆檔案的集合,這些檔案包括部署描述子、component interface,以及所有在部署階段產生的輔助classes。此時不存在任何entity bean instance

2.       Pooled State

EJB Server啟動後,它會讀取相關檔案,產生一些entity beaninstance。在產生entity bean instance後,EJB Container會呼叫entity beansetEntityContext()方法,將EntityContext物件賦予entity bean instanceEntityContext物件記載著該entity bean instance所在的EJB Container的狀態。在entity bean instance被賦予EntityContext後,就被放到集區中,進入Pooled State。此時的entity bean只有預設值,並不代表資料庫裡的任何資料。

有幾種情況可以使得在Pooled State中的entity bean instance離開集區並被資源回收。首先,EJB Server可視需要增加或減少集區中的entity bean instance,以有效利用系統資源並在效能上有較佳表現。其次,當停止EJB Server時,EJB Container也會釋放所有在集區中的bean instance。最後,當entity bean instance出現不可修復的錯誤時,EJB Container也會將之移出集區,並以集區中其他entity bean instance取代之。

entity bean instance被移出集區之後與被資源回收之前,EJB Container會呼叫其unsetEntityContext()方法,以通知該entity bean instance即將被毀滅。

3.       Ready State

client端呼叫entity beanhome interface上的create()方法時,EJB Server會產生一個EJB Object,並從集區中取出一個entity bean與之結合,此時entity bean進入Ready State。接著EJB Container會依序呼叫在entity bean instance上與create()對應的ejbCreate()ejbPostCreate()方法。當ejbPostCreate()方法執行完成後,create()方法會回傳一個EJB Objectreferenceclient端,此時entity bean instanceEJB Object就可以服務來自client端的請求。

前面介紹Pooled State時曾提到EJB Container為了有效利用系統資源,會視需要增加或減少集區中的entity bean instance,同樣地,EJB Container也會視需要在Pooled StateReady State之間移動entity bean instanceEntity bean instanceReady State移至Pooled State叫做Passivation過程,從Pooled State移至Ready State則叫做Activation過程。在Passivation過程中,EJB Container會呼叫entity beanejbStore()方法,將目前entity bean instance的資料寫回資料庫,再呼叫entity beanejbPassivate()方法通知該entity bean instance其即將被移回Pooled StateejbPassivate()方法執行完成後,entity bean instance就與EJB Object分離並回到Pooled State

Activation過程預設了某entity bean先前的Passivation過程。在Passivation過程結束後,原先與EJB Object結合的entity bean instance回到Pooled State,而EJB Object則維持其與client端的連線。一旦client再度呼叫EJB Object上的方法時,EJB Container就從集區中任意取出一entity bean instance與既存的EJB Object結合,繼續服務來自client端的請求。在這過程中,EJB Container呼叫entity beanejbActivate()方法,通知該entity bean instance準備更新來自資料庫的資料,再呼叫entity beanejbLoad()方法通知該entity bean instance資料已經重新寫入,準備服務來自client端的請求。

最後一種從Ready Stateentity bean instance移回Pooled State的情況是client端呼叫EJB ObjectEJB Home上相關的的remove方法時,EJB Container會呼叫entity bean上的ejbRemove()方法,此時系統會刪除資料庫中與該entity bean instance相對應的資料。ejbRemove()方法執行完成後,該entity bean instance就被移回Pooled State

posted @ 2008-12-04 11:30 paulwong 阅读(286) | 评论 (0)编辑 收藏

J2EE簡介

1. J2EE (Java 2 Enterprise Edition)架構

近年來,J2EE平台在企業內資訊應用系統的應用上,佔有越來越重要的地位,今天的內容,將先就J2EE的概念提供說明,而實作上的範例,我們將在後續的主題陸續提出討論。
J2EE平台提供了能支援多層(Multi-Tier)企業應用程式的技術規格,這些技術主要分為三部份,分別是元件(Component),服務(Service)及通訊(Communication)。
元件技術讓程式開發者能夠遵循標準方式建立可重用的元件,相同的企業邏輯可因此運用在不同的應用程式內。在這些元件中,可以透過標準化的API使用執行環境提供的服務以及準備好的資源,比如資料庫、名稱及目錄服務(Naming and Directory)、訊息服務(Messaging Service),並可使用交易(Transaction)管理等,這樣一來,也簡化了程式開發的複雜性。在多層架構下,各層間的通訊在J2EE中也提供解決方法。以下將針對元件及常見服務,提供介紹。


J2EE 的大略架構如下圖:

Client端如為Web Browser,則須穿過Web Container,透過JSP及Servlet呼叫EJB的方法(Method),以存取後端資料。如Client為使用Swing撰寫之Application,則不須經過Web Container,而是直接呼叫EJB提供的方法。


2. EJB

EJB(Enterprise JavaBeans)可看成是一組API的定義,它定義了的EJB開發及部署(Deploy)的方法以及架構。EJB具有架構上的延展性、可定義對交易的反應,而且能設定對不同使用者的存取控制。由於EJB Container提供了Networking, Transaction, Security及Bean Instance Pooling等Logic,因此EJB在EJB Container內執行,可以不須煩惱網路等問題,且可使用EJB Container已經準備好的服務。EJB分為三種,分述如下。

2.1. Session Bean
Session Bean通常在一個Client與EJB的一個Session期間存在,但是真實物件的生命週期是由EJB Container控制。一般的應用是將商業邏輯拆解成一個一個方法(Method),再將這些方法在Session Bean中實作,讓EJB Client呼叫使用。Session Bean又分為Stateful及Stateless,而Stateless Session Bean能支援同時多人使用,除非一定要儲存狀態於Session Bean內,否則建議使用Stateless Session Bean。

2.2. Entity Bean
Entity Bean是表達資料儲存內容的EJB,雖然Entity Bean目前Persistence作法以將資料存放在Database為主,但不表示僅能使用關聯式資料庫儲存。就實務上來看,在資料查詢所須的SQL Statement較複雜的情況下,則不建議使用Entity Bean,此時直接使用JDBC存取資料庫會是比較方便的作法。

2.3. MDB(Message-driven Bean)
MDB顧名思義是由Message驅動的EJB,提供J2EE平台對非同步訊息(Asynchronized Messages)的處理能力。目前MDB僅能處理透過JMS(Java Message Service)傳遞的Message,其運作原理是實作一個onMessage方法,這樣當JMS內有Message要交由MDB處理時,會由EJB Container從Pool中選一個MDB出來,接著呼叫它的onMessage方法。

3. J2EE平台提供之服務及API

接下來介紹一些常用的J2EE的API,這些服務執行在J2EE Server內,可在Web Container及EJB Containaer內使用。

3.1. JDBC

JDBC (Java DataBase Connectivity)主要提供連結至Data Source的方式,Data Source不只是Database,還包括檔案。

JDBC Driver 主要的工作有三項:
a. 建立和Data Source之間的Connection。
b. 送出相關的SQL Statement。
c. 將結果傳回。

JDBC除了可以送出一般的SQL Statement之外,也可以呼叫寫好在Database裡的Stored Procedure。

由於各種Database的連結方式可能都不同,使用JDBC的好處是,不須要自己去寫存取 Database的相關程式,只要使用DBC的API,搭配相關的Driver,就可以讓程式存取各種不同的Database了。
目前最新版的JDBC 規格是 4.0,但是,在使用JDBC的相關功能之前,要先確認所使用的JDBC Driver支援到哪一個版本。

JDBC最新的一個Implement叫做RowSet Implementation Specification,是就JDBC原本提供的RowSet再做更進一步的強化。這個部份將會被納入J2SDK1.5中。


3.2. Servlet
Servlet是用來處理Request和Response的一些Class,主要是處理HTTP Protocol。它的Package主要有javax.servlet和javax.servlet.http。

在最新的Servlet 2.3 規格裡,新增了一個叫做「Filter」的功能,Filter的作用是在Request送出之後、以及Response接到之前,再做一個判斷篩選的動作。這個Filter最常用在Reuse原本的程式的時候,為了確保原本的程式結構不被修改,但又須要加上一些新的設定時,就可以使用Filter去做處理,Filter所做的事情也都可以被Log下來。


3.3. JSP
JSP的全名是JavaServer Pages,算是Servlet技術的延伸,可以使用HTML或是XML。JSP提供了一個Create Web Content的簡便方式,在搭配JSTL(JavaServer Pages Standard Tag Library)使用的時候,由於JSTL提供了一些很簡便的Tag,所以在程式的撰寫和維護上都會容易許多。目前JSP 規格的最新版本是2.0。

早期在還沒有JSP的時候,程式和畫面的呈現都會放在Servlet裡,造成維護非常困難,在有JSP之後,可以將程式碼以及畫面切開,在維護上會比全部的東西都放在Servlet裡要方便得多。

3.4. JMS
JMS, Java Message Service, 提供了J2EE Components進行相關的Message的功能。一個JMS的應用程式可以分為以下幾個部份:
a. JMS Clients:是使用JMS API所開發的用來傳送/接收Message的應用程式。
b. Non-JMS Clients:這些應用程式並沒有使用JMS的API,而是使用Message System所提供的API。
c. Messages:定義好的一些用在Clients之間溝通的訊息。
d. JMS Provider:Message System所定義好的,使用JMS來開發的一些功能。
e. Administered Objects:提供給系統管理者方便使用的預先定義好的JMS Objects。


3.5. JNDI
JNDI, Java Naming and Directory Interface,主要是提供Naming和Directory的相關功能,使得應用程式可以更具可攜性(Portable)。應用程式中若使用JNDI相關的API來開發,只要在設定的時候指定JNDI的名稱,就可以存取不同的Directory裡的屬性(Attribute)。JNDI的相關Package有:javax.naming、javax.naming.directory、javax.naming.event、javax.naming.ldap、和javax.naming.spi。

3.6. Transactions
J2EE提供了兩組Transactions相關的規格,分別是JTA(Java Transaction API)和JTS(Java Transaction Services)。

JTA提供了控制Transaction的相關API,程式是去呼叫JTA的API,再由JTA來交給JTS做控制。所提供的Package有javax.transaction和javax.transaction.xa。目前不Support NestedTransactions。在EJB裡,建議使用Bean-managed Transaction,也就是Session Bean或是Message-driven Bean,且在使用的時候,必須先定義目前要用的是JDBC的Transaction或者是JTA的Transaction。

3.7. Web Services
在J2EE的架構中,提供了許多有關Web services的API,這些API都是以XML的語法來定義。
Web Services 相關的API有 JAXP(Java API for XML Processing)、JAXR(Java API for XML Registries)、JAX-RPC(Java API for XML-based RPC)和SAAJ(SOAP with Attachments API for Java)等。
簡單介紹一下這幾個API:
a. JAXP:這組API被定義在javax.xml.parser這個Package裡,這個Package提供了SAX和DOM相關的Parser功能。
b. JAXR:主要是提供存取不同的XML Registry的功能。XML Registry目前最有名的是ebXML和UDDI。
c. SAAJ:主要是依循 SOAP這個標準,提供了Message和Connection的相關功能。

posted @ 2008-12-04 11:29 paulwong 阅读(702) | 评论 (0)编辑 收藏

EJB的基本觀念介紹

從J2EE推出以來,已經逐漸為企業所熟知,投入J2EE相關技術的資訊從業人員也不斷增加。在J2EE的各項技術中,EJB 是十分值得投資的新技術。

你可能已經知道EJB是Enterprise Java Bean的縮寫,但是可能還不知道EJB的用處和架構。本文的主要目的就是讓讀者先有初步的認識,之後在接下來的各期爪哇藍報中再分別介紹更為入的應用介紹。
1. 基本架構及名詞介紹

EJB從意義上來說,是一種「技術規範」,而不是一種產品,
‧Bean Instance :表示在記憶體中實際產生的物件。一個 Bean Class 可以產生多個 Bean Instance 。Bean Instance 才是真正執行 EJB method 的物件。

‧Container:容器是可提供特定元件(Components)服務的標準執行環境。例如,Web Container必須提供必要的程序(呼叫特定頁面、處理程式等),回應Client端的需求,並將處理結果傳回Client端。

‧EJB Container: 是EJB 標準執行環境,所有 EJB 的產生,或是消滅,或是執行等等,均透過 EJB Container 來處理。當使用者呼叫某個EJB 的時候,實際上也是透過 EJB Container 來執行。

‧Deploy:一個寫好的 EJB 並不能單獨執行,他必須被「放」到EJB Container 之後才能夠執行,而這個動作就是Deploy。Deploy通常只是執行某個動作、按鈕,之後的動作就交由Application Server自行處理。

‧EJB Client:負責使用者介面呈現的元件,可能是JSP/Servlet,或者是一個Standalone Java Application。

‧Message Queue:在程式中要傳達的資料片斷稱為Message,存在於記憶體中,而Message都可經由Message Queue提供給不同的Process進行處理。Message Queue儲存了每個的Message的位址(Address)、型態(Type)、大小(size)、指到下一個Message的指標(pointer)等,它的資料結構基本上是一個Linked List。

2. EJB的種類及用處

EJB 依照特性的不同,區分為幾種。
‧Session Bean:主要的目的是讓程式開發者將邏輯層抽離,這些「邏輯」通常就是一個應用程式中的Business Logic,在整個系統開發中佔有相當重要的一部份。系統開發者可以多加利用Session Bean,將複雜的邏輯放在 Session Bean 的Method中。

  ‧ Stateful Session Bean:可以記錄呼叫者的狀態,因此通常來說,一個使用者會有一個相對應的 Stateful Session Bean 的實體(Instance)。

‧Stateless Session Bean:也是邏輯元件,但是他卻不負責記錄使用者狀態,也就是說當使用者呼叫 Stateless Session Bean 的時候,EJB Container 並不會找尋特定的 Stateless Session Bean 的實體來執行這個 method。

‧Entity Bean:它的角色是主要是資料元件,主要目的在於提供資料,讓系統開發人員直接將Entity Bean 當作程式中所要用到的資料;至於 Entity Bean如何存取一個Relational Databse或LDAP,就可以作為另外一項獨立的事情。

  ‧Bean-Managed Persistence(BMP):由名稱上就可以直接了解到BMP是由Bean自行維護資料的一致。`而Bean從資料庫取得資料後,BMP 中需要自行宣告欄位來存放這些資料,相關的 JDBC 語法等程式,也都須要自行撰寫。適用於開發人員想要完全控制 BMP 的資料存取行為時。

‧ Container-Managed Persistence(CMP):
相對於BMP,CMP是由 EJB Container 負責維護資料。撰寫 CMP 的程式設計師並不需要撰寫大多數的 JDBC 語法,通常只需要撰寫Deployment Description,就可以產生 CMP ;實際上的程式碼是 EJB Container在Deploy EJB 的時候所產生。CMP似乎有助於快速開發系統(大部份的工作都交給EJB Container了嘛),但是須要配合使用支援 CMP 的Application Server,而截至目前為止,每一家不同Application Server對CMP 的支援程度也不大相同。

‧ Message Driven Bean:
主要的目的在於反應 Message Queue 中的事件,當 Message Queue 中有訊息傳入時,Message Driven Bean 可以被觸發,做出對應的反應;所以Message Driven Bean可以說是主動反應,而不是「呼叫某個Method」這樣的方式被動觸發。

其中 Session Bean 與Entity Bean在 EJB 規格 1.x 的時候就已經存在了,而 Message Driven Bean 則出現在 EJB 2.0 的規格中。

posted @ 2008-12-04 11:27 paulwong 阅读(505) | 评论 (0)编辑 收藏

在jsp页面中使用oscache标签实现可配置的页面缓存

最近在学习oscache的相关内容,写点东西作为巩固

如果在jsp中使用如下标签

<cache:cache key="foobar" scope="session">  
          some jsp content   
</cache:cache> 


那么这中间的一段jsp代码将会以key="foobar"缓存在session中,任何其他页面中使用这个key
的cache标签都能共享这段存在缓存中的执行结果

考虑一个需求,一个页面是有许多个不同的jsp文件拼出来的
可能在页首有随机的广告,登录用户的信息,系统的即时信息,固定的目录信息等等
这其中可以考虑将固定的目录信息放入缓存中,而其他动态信息则即时刷新
再进一步考虑 有时候页面之间的信息是关联的,只有当其中一条信息的内容变化了才需要去刷新
对于这种需求就可以考虑在<cache:cache/>标签中配置group属性,将不同的具有关联关系的cache内容
分组,这样oscache会自动的帮你检查该组缓存内容的变化情况,如果有任何一子成员组的内容变化了
则会执行刷新,这样就可以在页面实现数据的动态同步
代码如下:(来源oscache:groupTest.jsp )



<%@ page import="java.util.*" %>  
<%@ taglib uri="http://www.opensymphony.com/oscache" prefix="cache" %>  
   
 
<head>  
 
<title>Test Page</title>  
 
<style type="text/css">  
 body 
{font-family: Arial, Verdana, Geneva, Helvetica, sans-serif}  
 
</style>  
 
</head>  
 
<body>  
   
 
<href="<%= request.getContextPath() %>/">Back to index</a><p>  
 
<hr>Flushing 'group2'<hr>  
 
<cache:flush group='group2' scope='application'/>  
 
<hr>  
 
<cache:cache key='test1' groups='group1,group2' duration='5s'>  
     
<b>Cache Time</b><%= (new Date()).getTime() %><br>  
     This is some cache content test1 that is in 'group1' and 'group2'. Normally it would refresh if it  
     was more than 5 seconds old, however the 
<cache:flush group='group2' scope='application'>  
     tag causes this entry to be flushed on every page refresh.
<br>  
 
</cache:cache>  
 
<hr> 



这里有两个cache分组group1和group2,将group2设置为每次都执行刷新,所以test1为key的cache每次刷新页面内容都是重新执行过的

<cache:cache key='test2' groups='group1' duration='5s'>  
    
<b>Cache Time</b><%= (new Date()).getTime() %><br>  
     This is some cache content test2 that is in 'group1' (refreshes if more than 5 seconds old)
<br>  
 
</cache:cache>  
 
<hr> 


而test2只有当间隔时间超过5秒才会更新内容

 <cache:cache key='test3' duration='20s'>  
     
<b>Cache Time</b><%= (new Date()).getTime() %><br>  
     This is some cache content test3 that is in 'group1' and 'group2'. The groups are added using the 
<cache:addgroup /> tag.<br>  
     
<cache:addgroup group='group1'/>  
     
<cache:addgroup group='group2'/>  
 
</cache:cache>  
 
<hr>  
 
<cache:cache key='test4' duration='20s'>  
     
<b>Cache Time</b><%= (new Date()).getTime() %><br>  
     This is some cache content test4 that is in 'group1' and 'group2'. The groups are added using the 
<cache:addgroups /> tag.<br>  
     
<cache:addgroups groups='group1,group2'/>  
</cache:cache>  
 
<hr>  
 
</body>  
</html> 


<cache:addgroup group='{you_group}'/>可以将所在的cache加入存在的group中

posted @ 2008-02-19 22:28 paulwong 阅读(1468) | 评论 (0)编辑 收藏

用Hibernate实现领域对象的自定义字段

     摘要: 导言 在开发企业级业务应用(企业规模)时,客户往往要求在不修改系统源代码的情况下对应用对象模型的扩展性提供支持。利用可扩展域模型可以实现新功能的开发,而不需要额外的精力和成本 应用的使用周期将被延长;  外部因素改变时,系统工作流也可以随之被修改; 已经被部署的应用可以被“设定”,使其符合企业的特定情况。 完成以上功能...  阅读全文

posted @ 2008-01-23 11:57 paulwong 阅读(2137) | 评论 (1)编辑 收藏

struts2笔记:与spring2集成


struts2基本上就是webwork的翻版,所以迁移过程倒是很简单,只需要修改下配置文件和一些包名就可以了。如果在Eclipse、Netbeans这些集成开发工具的帮助下,记不清包名也很容易找到想要的类的,呵呵。


在Eclipse下建立一个Dynamic Web Application。


从struts2.0.6的lib目录中复制下面的库文件到WEB-INF/lib目录下:
commons-logging-1.1.jar
freemarker-2.3.8.jar
ognl-2.6.9.jar
struts-api-2.0.6.jar
struts-core-2.0.6.jar
struts-spring-plugin-2.0.6.jar
xwork-2.0.0.jar


从spring中lib目录中复制下面的库文件到WEB-INF/lib目录下:
spring.jar


修改web.xml,增加一个struts的分派器filter,映射所有的url-pattern,再增加一个spring的ContextLoaderListener监听器。修改后的内容如下:


<?xml version="1.0" encoding="UTF-8"?>   
<web-app id="WebApp_ID" version="2.4"   
    xmlns
="http://java.sun.com/xml/ns/j2ee"   
    xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"   
    xsi:schemaLocation
="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">   
    
<display-name>struts2tutorial</display-name>   
        
    
<filter>   
        
<filter-name>struts2</filter-name>   
        
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>   
    
</filter>   
        
    
<filter-mapping>   
        
<filter-name>struts2</filter-name>   
        
<url-pattern>*.action</url-pattern>   
    
</filter-mapping>   
        
    
<welcome-file-list>   
        
<welcome-file>index.jsp</welcome-file>   
    
</welcome-file-list>   
        
    
<listener>   
        
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>   
    
</listener>   
        
</web-app>   

 

写一个简单的Action,HelloWorld:


package tutorial;    
import com.opensymphony.xwork2.ActionSupport;    
public class HelloWorld extends ActionSupport {    
   
    
public static final String MESSAGE = "Struts is up and running ";    
   
    
public String execute() throws Exception {    
        setMessage(MESSAGE);    
        
return SUCCESS;    
    }
    
   
    
private String message;    
   
    
public void setMessage(String message){    
        
this.message = message;    
    }
    
   
    
public String getMessage() {    
        
return message;    
    }
    
}
   


在源文件路径下(项目的src目录)增加struts.xml配置action。这个文件是集成spring的关键所在,这里面描述有如何将spring2集成到struts2的相关信息:


<!DOCTYPE struts PUBLIC    
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    
    "http://struts.apache.org/dtds/struts-2.0.dtd"
>   
<struts> 
    
<!-- 下面这句表明对象是由spring负责产生的.加上这句后,struts会产生让spring负责产生bean,如果spring不能产生bean,则由struts自己产生.也可以在struts.properties文件内定义这个属性.--> 
    
<constant name="objectFactory" value="spring"></constant>   
    
<package name="struts2tutoial" extends="struts-default" namespace="/">   
        
<!-- 注意,现在action的class属性不再是类的名字了,而是在spring中的bean的id,详细信息请看下面的spring的bean配置文件applicationContext.xml --> 
        
<action name="HelloWorld" class="helloWorld">   
            
<result>/helloWorld.jsp</result>   
        
</action>   
        
<!-- Add your actions here -->   
    
</package>   
</struts>   


在WEB-INF/目录下增加spring的bean配置文件applicationContext.xml:


<?xml version="1.0" encoding="UTF-8"?>   
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">   
<beans>   
   
    
<bean id="helloWorld" class="tutorial.HelloWorld"></bean>   
   
</beans>  


配置很简单,只有一个bean。

最后,在WebContent目录下增加helloWorld.jsp:


<%@ taglib prefix="s" uri="/struts-tags" %>   
   
<html>   
    
<head>   
        
<title>Hello World!</title>   
    
</head>   
    
<body>   
        
<h2><s:property value="message" /></h2>   
    
</body>   
</html> 

posted @ 2007-07-16 23:38 paulwong 阅读(562) | 评论 (0)编辑 收藏

Struts-Menu结合角色权限的应用

     摘要: STRUTS-MENU简介:STRUTS-MENU支持静态和动态菜单,数据来源和显示方式分开,菜单文字国际化,权限。 <menu:useMenuDisplayer name="Velocity" config="/framework/res/menucomp/templates/xtree.html"  bundle="org.apache.stru...  阅读全文

posted @ 2007-07-16 23:07 paulwong 阅读(1817) | 评论 (1)编辑 收藏

Spring Module---cache

项目需要缓存,google了一下,发现spring module有现成的东西可用,随即拿来看看。发现还是比较好用的。
改cache采用了aop的方式进行cache的写入和刷出。使用spring风格,上手容易。
系统负载不高,因此对于该缓存方法的性能等等不做评价,目前满足需要。
使用方法:
有这么几个概念需要提前知道1.XXCacheFacade,比如如果是oscache,那么XX就是oscachefacade.该类负责缓存的写入和刷出

<bean id="oscacheFacade" class="org.springmodules.cache.provider.oscache.OsCacheFacade">  
    
<property name="failQuietlyEnabled" value="true"/>  
    
<property name="cacheManager">  
        
<bean id="oscacheManager" class="org.springmodules.cache.provider.oscache.OsCacheManagerFactoryBean"/>  
    
</property>  
  
</bean>  


里面的cacheManager必须要有,改类负责提供底层具体的cache实现,比如oscache或者EHcache等。
2.MethodMapCachingInterceptor这个拦截器是官方提供的同类型的拦截器之一,根据方法名,参数匹配拦截。

<bean id="cachingInterceptor001" class="org.springmodules.cache.interceptor.caching.MethodMapCachingInterceptor">  
    
<property name="cacheProviderFacade" ref="oscacheFacade"/>  
    
<property name="cachingModels">  
        
<props>  
            
<prop key="com.company.jncz.TestItIF.get*">groups=aa;refreshPeriod=10</prop>  
            
<prop key="com.company.jncz.TestItIF.load*">groups=bb;refreshPeriod=10</prop>  
        
</props>  
    
</property>  
  
</bean>  


注意cachingModels。有两种方式写法,一种是上面看到的使用props另一种是使用Map.在有些情况下只能使用Map方式,下面解释

<map>  
  
<entry key="com.company.jncz.TestIt.get*">  
    
<ref local="oscacheCachingModel"/>  
  
</entry>  
</map>  

 

 

<bean id="oscacheCachingModel" class="org.springmodules.cache.provider.oscache.OsCacheCachingModel">  
    
<property name="groups">  
            
<list>  
               
<value>aa</value>  
               
<value>bb</value>  
            
</list>  
       
</property>  
    
<property name="refreshPeriod" value="10"/>  
 
</bean>  


尤其当groups(对于oscache来说是groups)的值不止一个的时候,就需要使用map的方式。
否则不生效(也许还有什么我没有注意到).另外需要注意的是对于model来说他的key很重要。有以下需要注意:如果AImpl是A接口的实现类,而且你在其他地方使用时都是用A接口来声明的,那么key就必须写成接口的全限定名比如:com.company.jncz.A.getXX,否则无法识别。

 

对于与cachingModel相对应的flushingModel写法是类似的,参考api很容易写出来。

最后

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
        
<property name="beanNames">  
            
<value>*Service</value>  
        
</property>  
        
<property name="interceptorNames">  
            
<list>  
                
<value>cachingInterceptor001</value>  
                
<value>flushingInterceptor001</value>  
            
</list>  
        
</property>  
  
</bean>  
  
<bean id="testService" class="com.company.jncz.TestItStub"/>  


这些不做介绍。
总之比较简单。这两天感冒,昏昏沉沉,不知道有没有表达清楚。。。。

 

自己看了一眼,的确没说清楚,要清楚的几个概念是cacheFacade.CachingModel.FlushingModel.CachingInterceptor.FlushingInterceptor.这些算是比较重要的。其他aop内容略。caching拦截器拦截某方法,根据cachingModel定义的规则由cacheFacade将之放入cache。flushing拦截器拦截到某方法,根据flushingModel定义的规则由cacheFacade将对应的cache清除。嗯,基本上流程就这样子了。

posted @ 2007-07-16 17:01 paulwong 阅读(1386) | 评论 (0)编辑 收藏

仅列出标题
共110页: First 上一页 102 103 104 105 106 107 108 109 110 下一页