PetStore 中EJB 的設(shè)計模式
1/1
目錄
劉兵(
bliu76@yeah.net)
目錄..............................................................................................................................................1
PetStore 中EJB 的設(shè)計模式............................................................................................................3
1. 概述..........................................................................................................................................3
2. 模式分類..................................................................................................................................4
2.1. Data Access Object 模式..........................................................................................4
2.1.1. 意圖...................................................................................................................4
2.1.2. 動機...................................................................................................................4
2.1.3. 結(jié)構(gòu)...................................................................................................................5
2.1.4. PetStore 的例子................................................................................................6
2.1.4.1 概述...................................................................................................6
2.1.4.2 CatalogEJB................................................................................................8
2.1.4.3 CatalogDAO..............................................................................................9
2.1.4.4 CatalogDAOImpl ......................................................................................9
2.1.4.5 CatalogDAOFactory................................................................................10
2.1.5. GOF 模式關(guān)系................................................................................................10
2.1.4.6 Bridge 模式.............................................................................................10
2.1.4.7 Adapter 模式...........................................................................................11
2.2. Value Object 模式...................................................................................................11
2.2.1. 意圖.................................................................................................................11
2.2.2. 動機.................................................................................................................13
2.2.3. 結(jié)構(gòu).................................................................................................................14
2.2.4. PerStore 的例子..............................................................................................14
2.3. Session Façade 模式...............................................................................................16
2.3.1. 意圖.................................................................................................................16
2.3.2. 動機.................................................................................................................16
2.3.3. 結(jié)構(gòu).................................................................................................................17
2.3.4. PetStore 中的例子..........................................................................................18
2.1.4.8 概述.................................................................................................18
2.1.4.9 ShoppingClientFacadeLocalEJB.............................................................18
2.3.5. GOF 中Facde 模式........................................................................................19
2.4. Fast-Lane Reader 模式...........................................................................................20
2.4.1. 意圖.................................................................................................................20
2.4.2. 動機.................................................................................................................20
2.4.3. 結(jié)構(gòu).................................................................................................................21
2.4.4. PetStore 中的例子..........................................................................................21
PetStore 中EJB 的設(shè)計模式
2/2
2.1.4.10 CatalogDAO....................................................................................21
2.1.4.11 CatalogWebImpl..............................................................................21
2.1.4.12 ProductListTag ................................................................................22
2.5. Page-by-Page Iterator 模式.....................................................................................23
2.5.1. 意圖.................................................................................................................23
2.5.2. 動機.................................................................................................................24
2.5.3. 結(jié)構(gòu).................................................................................................................25
2.5.4. PetStore 的例子..............................................................................................25
2.1.4.13 CatalogDAOImp .............................................................................25
2.1.4.14 ProductItemListTag.........................................................................26
2.5.5. GOF 的Iterator 模式......................................................................................27
2.6. ServiceLocator 模式...............................................................................................27
2.6.1. 意圖.................................................................................................................28
2.6.2. 動機.................................................................................................................28
2.6.3. 結(jié)構(gòu).................................................................................................................28
2.6.4. PetStore 中的例子..........................................................................................29
2.1.4.15 ServiceLocatorImpl.........................................................................29
2.1.4.16 我們項目的例子.............................................................................30
2.6.5. GOF 模式........................................................................................................32
2.1.4.17 Singleton 模式................................................................................32
2.7. Local 模式...............................................................................................................33
2.7.1. 意圖.................................................................................................................33
2.7.2. 動機.................................................................................................................33
2.7.3. 結(jié)構(gòu).................................................................................................................33
2.7.4. PetStore 例子..................................................................................................35
2.8. CMR 模式...............................................................................................................35
2.8.1. 意圖.................................................................................................................35
2.8.2. 動機.................................................................................................................35
2.8.3. 結(jié)構(gòu).................................................................................................................35
2.8.4. PetStore 中的例子..........................................................................................36
2.9. 業(yè)務(wù)代表模式.........................................................................................................37
2.9.1. 意圖.................................................................................................................38
2.9.2. 動機.................................................................................................................38
2.9.3. 結(jié)構(gòu).................................................................................................................39
2.9.4. PetStore 中的例子..........................................................................................39
2.9.5. GOF 模式........................................................................................................41
2.1.4.18 Proxy 模式......................................................................................41
3. EJB 模式關(guān)系.........................................................................................................................42
4. 相關(guān)的資料.............................................................................................................................43
5. 總結(jié)........................................................................................................................................43
PetStore 中EJB 的設(shè)計模式
3/3
PetStore 中EJB 的設(shè)計模式
Liubing (
bliu76@yeah.net)
1. 概述
通過分析數(shù)據(jù)模型,和實際操作PetStore 我們大概對它的數(shù)據(jù)模型有所了解。現(xiàn)在開始
分析系統(tǒng)EJB 層的設(shè)計模式。首先什么是模式?看Gof 的《設(shè)計模式》的定義,就是對被
用來在特定場景下解決一般設(shè)計問題的類和相互通信的對象描述。唉!太深沉了。一頭霧水。
其實,就是一些經(jīng)驗,并且經(jīng)過科學(xué)整理,可以在某種場合下反復(fù)使用,解決一些問題。當(dāng)
然在《設(shè)計模式》一書羅列出23 中模式,并且進行了詳細描述。今天我們所說的模式,是
PetStore 中的EJB 設(shè)計經(jīng)驗。
關(guān)于設(shè)計模式,我有很多感觸,Gof 的書我不知看了多少遍,可總是不太明白,我?guī)啄?br>沒有使用C++了,里面的例子,看著很不爽。板橋先生網(wǎng)上的例子很簡單明了,但是經(jīng)過一
段時間的學(xué)習(xí),有點不盡興的感覺。于是又看了其他的幾本書,心中有了一些感覺,可是實
際寫代碼很難用上,并且現(xiàn)在項目使用J2EE,于是我決定分析PetStore 源碼,看看這些牛
人是怎樣使用模式的。在我們的項目開發(fā)中也照葫蘆畫瓢,使用一把。
關(guān)于PetStore 的模式,SUN 的站點列出了以下幾種模式,當(dāng)然其中的FrontController 屬
于Web 層的。
Pattern Intent
Data Access
Object
Decouple business logic from data access logic and adapt the resource being
accessed, so that the type of resource can change easily and independently.
Fast-Lane
Reader
Accelerate read-only data access by not using enterprise beans.
Front Controller
Centralize view management (navigation, templating, security, etc.) for a Web
application in a single object that handles incoming client requests.
Page-by-Page
Iterator
Efficiently access a large, remote list by retrieving its elements one sublist of
value objects at a time.
Session Facade Provide a unified, workflow-oriented interface to a set of enterprise beans.
Value Object
Efficiently transfer remote, fine-grained data by sending a coarse-grained
view of the data.
在《J2EE 核心模式》一書中列出了以下幾種模式,當(dāng)然包括了以上的幾種模式。這本書不
錯,可惜翻譯的很次。
業(yè)務(wù)代表
值對象
值對象組裝器
PetStore 中EJB 的設(shè)計模式
4/4
值對象列表
會話外觀
服務(wù)器定位
數(shù)據(jù)訪問對象
服務(wù)激發(fā)器
我們首先知道EJB 層有這些模式,我把這些模式簡單介紹一下,包括它的意圖,動機,
結(jié)構(gòu),然后看在PetStore 中使用了那些,又是怎樣使用的。我想把我所理解的寫出,如果不
對的地方,請大家指出。
2. 模式分類
2.1. Data Access Object 模式
這個模式SUN 上有詳細的描述,并且《程序員 6 期》中有板橋先生的一遍文章介紹了它。
這模式使用了GoF 中Bridge 和Adapter 模式。如果大家不熟悉,最好看下Gof 的介紹,現(xiàn)
在我感覺GoF 的書當(dāng)作一個模式參考手冊比較不錯。一般剛開始就看這本,很難看懂,這
樣就打消了大家的積極性,這年頭,有學(xué)習(xí)上進的想法就很不錯了。在被人打擊,太不好了。
2.1.1. 意圖
Decouple business logic from data access logic and adapt the resource being accessed, so that
the type of resource can change easily and independently.(算了我不翻譯了,實際就是分離業(yè)
務(wù)邏輯和數(shù)據(jù)讀取,把數(shù)據(jù)的讀取寫到了DAO 中。這樣增強了系統(tǒng)的靈活性。如果你看過
GoF 的書,這個口號你一定記憶有心(針對接口編程,而不是針對實現(xiàn)編程),當(dāng)然了老米
的態(tài)度決定一切也很有哲理。設(shè)計模式就是把調(diào)用與實現(xiàn)分離,如果你感覺,很羅嗦被分的
亂七八糟,實現(xiàn)一個東西要好多類和接口,這樣你就對設(shè)計模式有了一定的了解了。)
2.1.2. 動機
These problems can be avoided by removing data access logic from
enterprise beans and abstracting data access functionality into a
separate interface. Enterprise beans carry out their business logic
in terms of operations on that interface, which is implemented by a
data access object (DAO) appropriate for the type of resource being
used. (就是業(yè)務(wù)邏輯中不負責(zé)數(shù)據(jù)的存取,把它放到DAO 中,這些數(shù)據(jù)的
格式,提供商一旦發(fā)生改變,只需修改DAO 即可)
For example, the Java Pet Store application‘s OrderEJB component
accesses a database through its associated OrderDAO class, which knows
how to perform load, save, and find operations on order data in the
PetStore 中EJB 的設(shè)計模式
5/5
persistent store. Because the bean delegates its persistence-related
tasks to the DAO, it can concentrate on implementing business methods.
At deployment time, the application administrator configures the
implementation of OrderDAO to be one of OrderDAOCS, OrderDAOOracle, or
OrderDAOSybase, depending on whether an Cloudscape, Oracle, or Sybase
database is used. No matter what choice is made, the OrderEJB is
unaffected, because it is programmed to an interface, not to an
implementation.(很簡單,我就不翻譯了吧,要不就被我糟蹋原意了)。
不過我現(xiàn)在使用的是JB6.0+Weblogic6。1 開發(fā)bmp,我們大多使用了JB 的
向?qū)?,它自動生成了代碼,可是它沒有實現(xiàn)這種模式.在SessionBean 中我們
封裝了JDBC 的數(shù)據(jù)讀取,有點向這種模式。
2.1.3. 結(jié)構(gòu)
它使用了GOF 中的Bridge 和Adapter 模式。整個結(jié)構(gòu)圖如下:
大家可能看明白,其實就是在BusinessObject 中提供了業(yè)務(wù)邏輯方法,假如它必須要讀取
數(shù)據(jù),但是這個數(shù)據(jù)可能存在Oracle 數(shù)據(jù)庫中,又有可能存在excel 文件中,也許存在XML
文件中,如果我們在這個方法中直接讀取數(shù)據(jù),那就要寫這樣的語句
switch (DATA_TYPE){
case ORACLE:
通過JDBC 讀取Oracle 數(shù)據(jù)
break;
case Excel:
通過專門的API 進行讀取,Excel 文件
PetStore 中EJB 的設(shè)計模式
6/6
break;
case XML
通過JDOM 進行,分析XML 文件;
break;
}
這樣,業(yè)務(wù)邏輯中到處是數(shù)據(jù)的讀取,并且修改程序,很麻煩。于是這些牛人,想出一
個使用接口DAO(就是DataAccessObject),它什么具體的事都不做,就申明幾個方法,在
業(yè)務(wù)邏輯類中,只管調(diào)用它就行了,好像在說我能做什么,不要管我怎樣做,就想我們的銷
售接項目一樣,說我們公司什么事都可以做。但是項目接下以后,就由我們這些命苦的開發(fā)
人員來實現(xiàn)。最后也就是DAOImplementor 根據(jù)數(shù)據(jù)的不同有不同的具體類來讀?。ㄋ锌?br>能是DAOImplementor_ORACLE 類實現(xiàn)讀取Oracle 數(shù)據(jù)庫,DAOImplementor_EXCEL,
實現(xiàn)通過API 讀取Excel 文件,DAOImplementor_XML 實現(xiàn)讀取XML 文件)。這樣你可,
在業(yè)務(wù)邏輯類中,不負責(zé)數(shù)據(jù)的讀取,只關(guān)注業(yè)務(wù)邏輯的實現(xiàn),它只需調(diào)用DAO 獲得數(shù)據(jù),
真正實現(xiàn)數(shù)據(jù)的讀取是DAOImplementor_ORACLE 這樣的類。
我解釋的不知你是否明白,反正我是知道了。多看幾次就明白了,其實很簡單。
2.1.4. PetStore 的例子
2.1.4.1 概述
首先我們看UML 圖,這是PetStore 自帶UML 圖,我用Rose 畫還需要時間,他們使用
了一種叫ARGOUML 的工具,你可以下載,是免費的感覺遠不如Rose.
PetStore 中EJB 的設(shè)計模式
7/7
這其中使用了GoF 的工場模式,也是簡單工場模式,它負責(zé)使用那個具體實現(xiàn)類,好像
大家都可以干這活,它來選擇到底由誰來做,就是我們的人力資源的。
我們在仔細分析一下,就是在CatalogEJB 類中有一些業(yè)務(wù)邏輯,如getProduct,它來取
某項分類的產(chǎn)品,這樣也許讀取數(shù)據(jù)庫,也有可能讀取XML文件,于是它就調(diào)用CatalogDAO
的方法,來實現(xiàn),但是CatalogEJB 并不知道數(shù)據(jù)到底存在那里,它只管讀就行了??墒?br>CatalogDAO 也只是聲明這個方法,真正辛苦干事情的就是CatalogDAOImpl,它負責(zé)讀取數(shù)
據(jù)庫。我們不要忘記,在CatalogEJB 有個方法,它調(diào)用了工場,它來確定又誰來做。
唉,下面是我使用Rose 的逆向工程,獲得的UML 圖。
PetStore 中EJB 的設(shè)計模式
8/8
CatalogDAOFactory
getDAO()
(from dao)
CatalogDAOImpl
getDataSource()
getCategory()
getCategories()
getProduct()
getProducts()
getItem()
getItems()
searchItems()
(f rom dao )
CatalogEJB
ejbCreate()
setSessionContext()
ejbRemove()
ejbActivate()
ejbPassivate()
destroy()
getCategory()
getCategories()
getProducts()
getProduct()
getItems()
getItem()
searchItems()
<<EJBSession>>
CatalogDAO
getCategory()
getCategories()
getProduct()
getProducts()
getItem()
getItems()
searchItems()
(from dao)
CatalogLocalHome
create()
(f ro m ej b)
2.1.4.2 CatalogEJB
public class CatalogEJB implements SessionBean {
//那個光說話,不做是的家伙,真正做事CatalogDAOImpl 類,CatalogEJB 不知道,
其實現(xiàn)實生活中就有這種事情
protected CatalogDAO dao;
public void ejbCreate() {
try {
//使用工程模式,產(chǎn)生DAO
dao = CatalogDAOFactory.getDAO();
} catch (CatalogDAOSysException se) {
}
}
PetStore 中EJB 的設(shè)計模式
9/9
//獲得產(chǎn)品信息
public Page getProducts(String categoryID, int start, int count, Locale l) {
try {
//調(diào)用DAO,實現(xiàn)業(yè)務(wù)邏輯
return dao.getProducts(categoryID, start, count, l);
}
catch (CatalogDAOSysException se) {
throw new EJBException(se.getMessage());
}
}
2.1.4.3 CatalogDAO
public interface CatalogDAO {
//聲明能力
public Page getProducts(String categoryID, int start, int count, Locale l)
throws CatalogDAOSysException;
}
2.1.4.4 CatalogDAOImpl
DAOpublic class CatalogDAOImpl implements CatalogDAO {
public Page getProducts(String categoryID, int start, int count, Locale l){
try {
c = getDataSource().getConnection();
ps = c.prepareStatement("select a.productid, name, descn "
+ "from (product a join "
+ "product_details b on "
+ "a.productid=b.productid) "
+ "where locale = ? "
+ "and a.catid = ? "
+ "order by name",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ps.setString(1, l.toString());
ps.setString(2, categoryID);
rs = ps.executeQuery();
//讀取數(shù)據(jù)庫
rs.close();
ps.close();
}
catch (SQLException se) {
PetStore 中EJB 的設(shè)計模式
10/10
}
}
2.1.4.5 CatalogDAOFactory
public class CatalogDAOFactory {
public static CatalogDAO getDAO() throws CatalogDAOSysException {
CatalogDAO catDao = null;
try {
//依據(jù)系統(tǒng)配置的信息,產(chǎn)生一個實現(xiàn)類
catDao = (CatalogDAO) Class.forName(className).newInstance();
} catch (NamingException ne) {
} catch (Exception se) {
}
return catDao;
}
}
2.1.5. GOF 模式關(guān)系
我可以簡單解釋以下。
2.1.4.6 Bridge 模式
結(jié)構(gòu)
意圖:將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化。
適用性
PetStore 中EJB 的設(shè)計模式
11/11
• 你不希望在抽象和它的實現(xiàn)部分之間有一個固定的綁定關(guān)系。例如這種情況可能是
因為,在程序運行時刻實現(xiàn)部分應(yīng)可以被選擇或者切換。
• 類的抽象以及它的實現(xiàn)都應(yīng)該可以通過生成子類的方法加以擴充。這時B r i d g e 模
式使你可以對不同的抽象接口和實現(xiàn)部分進行組合,并分別對它們進行擴充。
• 對一個抽象的實現(xiàn)部分的修改應(yīng)對客戶不產(chǎn)生影響,即客戶的代碼不必重新編譯。
2.1.4.7 Adapter 模式
它有兩種方式實現(xiàn)。比較簡單,我就不多說了。
2.2. Value Object 模式
值對象模式,在SUN 的站點上有詳細的描述,并且《J2EE 核心模式》上也有詳細描述,
其實這種模式,我們每天都在使用,目的就是減少網(wǎng)絡(luò)流量,提高效率,許多書上叫做的粗
粒度。和這種模式相關(guān)的還有復(fù)合實體,值對象組裝器,值列表處理器。
我感覺在項目開發(fā)中有一個人負責(zé)系統(tǒng)的全部entityBean,為每個entityBean 建立值對
象,并且建立他們之間的關(guān)系。其他的開發(fā)人員只管調(diào)用就行了,如果數(shù)據(jù)庫修改,它來修
改。這種方式,我建議大家使用。
2.2.1. 意圖
Efficiently transfer remote, fine-grained data by sending a
coarse-grained view of the data.
我們知道EJB 的調(diào)用使用了遠程方法,它的效率一般要遠低于本地方法的
調(diào)用,這樣我們要讀取一個對象,如果使用他的getXX 方法就多次調(diào)用了遠
程,效率很低,如果一次性讀到值對象,這就減少了遠程調(diào)用。
我們在實際開發(fā)中,一般為每個EntityBean 建一個值對象,并且在
entityBean 中的Home 接口中,增加一個create 方法,參數(shù)就是值對象. 并
且在接口中增加setData 和getData 方法。
Home 接口
public interface TAccountAcptRemoteHome extends javax.ejb.EJBHome
{
//在創(chuàng)建時,使用值對象,如果修改數(shù)據(jù)結(jié)構(gòu),接口不需改變,只修改
屬性就行了
public TAccountAcptRemote create(TAccountAcptModel data)
throws CreateException, RemoteException;
PetStore 中EJB 的設(shè)計模式
12/12
}
聲明接口(遠程或本地接口)
public interface TAccountAcptRemote extends javax.ejb.EJBObject {
//通過這個接口,一次性獲得值對象,不需分別使用getXX,減少網(wǎng)絡(luò)
調(diào)用次數(shù),提高效率
public TAccountAcptModel getData() throws RemoteException;
public void getData(TaccountAcptModel data) throws
RemoteException;
}
值對象
public class TAccountAcptModel implements java.io.Serializable {
public java.lang.String acceptId ;
public java.lang.String accountId ;
public java.lang.String ownerId ;
public java.lang.String accountName;
public java.lang.String accountAddr;
public java.lang.String accountZip ;
public java.lang.String bankId ;
public java.lang.String account ;
public java.lang.String payTypeId ;
public java.lang.String state ;
public java.lang.String postMode ;
public java.lang.String postAddr ;
public java.lang.String postZip ;
PetStore 中EJB 的設(shè)計模式
13/13
public java.lang.String postMan ;
public java.math.BigDecimal preSum ;
public java.sql.Date createDate ;
public java.sql.Date unsignDate ;
}
2.2.2. 動機
Some entities have a set of attributes that are always used together.
In the Java Pet Store application, the contact information of a
customer (city, state, zip code, etc.) is an example of one such group.
Suppose that in total, a customer‘s contact information is composed
of 15 individual attributes, each accessible by a corresponding getXXX
method in CustomerEJB. Then, every time a customer‘s contact information
is requested, 15 remote getXXX calls will be invoked on the CustomerEJB,
one for each attribute. This will incur heavy costs in network traffic
and EJB container resource usage.
The Java Pet Store application reduces these costs by adopting a
coarse-grained view of the fine-grained contact information. It
aggregates the contact information-related attributes of the
CustomerEJB into an instance of ContactInformation. This instance, or value
object, is then serialized and sent over the network to a requesting
client, where the object is deserialized. Subsequent read accesses go
through the value object rather than the remote entity object. Since
these accesses are local, they require no server communication and use
fewer resources.
PetStore 中EJB 的設(shè)計模式
14/14
2.2.3. 結(jié)構(gòu)
EnterpriseBean 業(yè)務(wù)對象,實現(xiàn)了業(yè)務(wù)邏輯
ValueObject 實現(xiàn)了串行化值對象。
2.2.4. PerStore 的例子
PetStore 中存在大量的例子,基本上每個EJB 中都可以找到它的蹤影。
PetStore 中EJB 的設(shè)計模式
15/15
如值對象ProfileInfo(一定要實現(xiàn)Serializable 接口,就是串行化)
public class ProfileInfo implements java.io.Serializable {
private String defaultPreferredLanguage = null;
private String defaultFavoriteCategory = null;
private boolean defaultMyListPreference = false;
private boolean defaultBannerPreference = false;
public ProfileInfo( String defaultPreferredLanguage,
String defaultFavoriteCategory,
boolean defaultMyListPreference,
boolean defaultBannerPreference) {
this.defaultPreferredLanguage = defaultPreferredLanguage;
this.defaultFavoriteCategory = defaultFavoriteCategory;
this.defaultMyListPreference = defaultMyListPreference;
this.defaultBannerPreference = defaultBannerPreference;
}
public String getPreferredLanguage() {
return defaultPreferredLanguage;
}
public String getFavoriteCategory() {
return defaultFavoriteCategory;
}
public boolean getBannerPreference() {
return defaultBannerPreference;
}
public boolean getMyListPreference() {
return defaultMyListPreference;
}
}
使用類,提高調(diào)用粗粒度,使用值對象
public abstract class CustomerEJB implements javax.ejb.EntityBean {
//一次調(diào)用,獲得值對象,提高效率
public abstract ProfileLocal getProfile();
//設(shè)置值對象
public abstract void setProfile(ProfileLocal profile);
}
PetStore 中EJB 的設(shè)計模式
16/16
2.3. Session Façade 模式
眾所周知在Gof 中有Façade(外觀)模式,我們只是把這種模式應(yīng)用到EJB 中罷了。它
的目的其實很明顯,就是給子系統(tǒng)提供一個一致的接口,這樣使系統(tǒng)業(yè)務(wù)邏輯集中,
使系統(tǒng)的業(yè)務(wù)邏輯和調(diào)用部分松耦合?,F(xiàn)在我是一般這些使用的,首先定義一些
EntityBean,和一些實現(xiàn)業(yè)務(wù)邏輯的SessionBean,然后在把這些業(yè)務(wù)邏輯封裝成
SessionBean 供web 層調(diào)用,一般在調(diào)用層不負責(zé)事務(wù)的管理,一個業(yè)務(wù)邏輯就是一個
獨立的事務(wù)。在Web 層其實只需獲得畫面的數(shù)據(jù),和簡單的校驗,然后直接提交到
EJB 層,進行處理,這樣使Web 的功能很簡單。
2.3.1. 意圖
Provide a unified, workflow-oriented interface to a set of enterprise
beans.
把SessionBean 用作Façade 以封裝參與業(yè)務(wù)的多個對象,提供給用戶統(tǒng)一的粗粒度訪問。
簡單一些,就是盡可能把事情放在EJB 層來做,接口越簡單越好,最好調(diào)用層不負責(zé)事務(wù),
一次調(diào)用就是一次事務(wù),累死EJB。
2.3.2. 動機
這些是抄J2ee 核心模式的內(nèi)容,顯得深沉一些。
通過隱藏了業(yè)務(wù)組件之間所有的復(fù)雜交互活動,向客戶提供一個簡單的接口
減少通過網(wǎng)絡(luò)并跨越服務(wù)層被直接暴露給客戶端的業(yè)務(wù)對象數(shù)目
向客戶隱藏業(yè)務(wù)組件之間的交互和相互
在下圖大家應(yīng)該能夠看明白一些,Client 如果處理一件事情,需要調(diào)用SessionBean1,
和兩個實體Bean,這樣客戶端要負責(zé)事務(wù),并且多次網(wǎng)絡(luò)調(diào)用,降低的效率。系統(tǒng)一定修改,
兩側(cè)都要大修。你應(yīng)該認為不爽吧。
如果我們把這些業(yè)務(wù)邏輯封裝在SessionFacade 里面,這樣調(diào)用很簡單,實際遠程調(diào)用
只需一次,接口也很簡單。
PetStore 中EJB 的設(shè)計模式
17/17
2.3.3. 結(jié)構(gòu)
我看下結(jié)構(gòu),其實就是在SessionFacade 中,封裝業(yè)務(wù)邏輯,簡化接口,大家應(yīng)該一看就明
白。
PetStore 中EJB 的設(shè)計模式
18/18
2.3.4. PetStore 中的例子
2.1.4.8 概述
在PetStore 中就使用了這種模式,不過大家一般在開發(fā)中都可能使用這種模式,只是自己不
知道罷了。
2.1.4.9 ShoppingClientFacadeLocalEJB
public class ShoppingClientFacadeLocalEJB implements SessionBean {
/*
* Asume that the customer userId has been set
*/
//它封裝了調(diào)用客戶的EntityBean
public CustomerLocal getCustomer() throws FinderException {
if (userId == null) {
throw new GeneralFailureException("ShoppingClientFacade: failed to look up
name of customer: userId is not set" );
}
try {
InitialContext ic = new InitialContext();
Object o = ic.lookup("java:comp/env/ejb/local/Customer");
CustomerLocalHome home =(CustomerLocalHome)o;
customer = home.findByPrimaryKey(userId);
} catch (javax.naming.NamingException nx) {
throw new GeneralFailureException("ShoppingClientFacade: failed to look up
name of customer: caught " + nx);
}
return customer;
}
//它封裝了產(chǎn)生客戶方法
public CustomerLocal createCustomer(String userId) {
try {
InitialContext ic = new InitialContext();
Object o = ic.lookup("java:comp/env/ejb/local/Customer");
CustomerLocalHome home =(CustomerLocalHome)o;
customer = home.create(userId);
this.userId = userId;
} catch (javax.ejb.CreateException ce) {
throw new GeneralFailureException("ShoppingClientFacade: failed to create
PetStore 中EJB 的設(shè)計模式
19/19
customer: caught " + ce);
} catch (javax.naming.NamingException nx) {
throw new GeneralFailureException("ShoppingClientFacade: failed to look up
name of customer: caught " + nx);
}
return customer;
}
}
2.3.5. GOF 中Facde 模式
意圖
為子系統(tǒng)中的一組接口提供一個一致的界面,F(xiàn) a c a d e 模式定義了一個高層接口,這個
接口使得這一子系統(tǒng)更加容易使用。
結(jié)構(gòu)
動機
• 當(dāng)你要為一個復(fù)雜子系統(tǒng)提供一個簡單接口時。子系統(tǒng)往往因為不斷演化而變得越
來越復(fù)雜。大多數(shù)模式使用時都會產(chǎn)生更多更小的類。這使得子系統(tǒng)更具可重用性,
也更容易對子系統(tǒng)進行定制,但這也給那些不需要定制子系統(tǒng)的用戶帶來一些使用
上的困難。F a c a d e 可以提供一個簡單的缺省視圖,這一視圖對大多數(shù)用戶來說已
經(jīng)足夠,而那些需要更多的可定制性的用戶可以越過f a c a d e 層。
• 客戶程序與抽象類的實現(xiàn)部分之間存在著很大的依賴性。引入f a c a d e 將這個子系
統(tǒng)與客戶以及其他的子系統(tǒng)分離,可以提高子系統(tǒng)的獨立性和可移植性。
• 當(dāng)你需要構(gòu)建一個層次結(jié)構(gòu)的子系統(tǒng)時,使用f a c a d e 模式定義子系統(tǒng)中每層的入
口點。如果子系統(tǒng)之間是相互依賴的,你可以讓它們僅通過f a c a d e 進行通訊,從
而簡化了它們之間的依賴關(guān)系。
PetStore 中EJB 的設(shè)計模式
20/20
2.4. Fast-Lane Reader 模式
我們都知道使用EJB 的效率低,但是在某些情況下效率很重要,這樣這些牛人就不使用
EJB 而是直接使用DAO 來讀取數(shù)據(jù)庫,這樣避免使用EJB 的事務(wù),串行化等。不過使用
EJB 的效率,是個問題,目前我們的營業(yè)系統(tǒng)因客戶數(shù)量的巨大,效率很低,我最頭痛的就
是這件事情,不知大家有沒有好的建議,我準備把我們系統(tǒng)中的查詢,報表統(tǒng)計改成不使用
EJB,也是這種模式。
2.4.1. 意圖
Accelerate read-only data access by not using enterprise beans。提高只讀數(shù)據(jù)的讀取,而不使用
EJB.
2.4.2. 動機
Sometimes it‘s more important to access a list of data efficiently,
than that the data in the list be up-to-date. For example, when a user
browses the Java Pet Store catalog, it‘s not crucial that what they
see on the screen be entirely consistent with what‘s in the database.
In the interests of usability, however, it is important that the
catalog data be displayed quickly–and thus retrieved quickly.
The Fast-Lane Reader pattern can accelerate the retrieval of large
lists of items from a resource. Instead of going through an enterprise
bean, an application accesses data more directly by going through a
data access object. This way, the application avoids the overhead
associated with using enterprise beans (remote method invocation,
transaction management, data serialization, etc.).
In the Java Pet Store application, when a user browses the catalog,
items are loaded from the database through the CatalogDAO instead of
the CatalogEJB component. The CatalogDAO is an example of a fast-lane
reader, because it facilitates quicker read access.
有些時候,高效地存取數(shù)據(jù)比獲得最新的數(shù)據(jù)更重要。在Java Pet Store 中,當(dāng)一個用戶瀏覽商
店的目錄時,屏幕與數(shù)據(jù)庫內(nèi)容吻合不是至關(guān)緊要的,相反,迅速顯示和重新獲得非常重要。
FLR 模式可以加速從資源中重新獲得大型的列數(shù)據(jù)項的速度,它不用EJB,而是更直接地通過
DAO 來存取數(shù)據(jù),從而消除EJB 的經(jīng)常開支(例如遠程方法調(diào)用、事務(wù)管理和數(shù)據(jù)序列化等)。
在Java Pet Store 這個例子中,當(dāng)一個用戶瀏覽目錄時,通過CatalogDAO(而不是CatalogEJB)
PetStore 中EJB 的設(shè)計模式
21/21
從數(shù)據(jù)庫加載數(shù)據(jù)項,而CatalogDAO 是一個Fast Lane Reader 的實例,使得讀訪問變得迅速
與DAO 模式不同的是,F(xiàn)LR 是一個優(yōu)化的模式,但不是要替代原有的訪問機制,而是作為補充
使其完備。當(dāng)你頻繁地只讀大型的列數(shù)據(jù)和不必存取最新的數(shù)據(jù)時,使用FLR 將是非常合適的。
2.4.3. 結(jié)構(gòu)
客戶端直接調(diào)用FastLaneReader,而不是使用EJB 來獲得數(shù)據(jù),當(dāng)然EJB 接口仍然保留。
2.4.4. PetStore 中的例子
2.1.4.10 CatalogDAO
定義數(shù)據(jù)的存取。使用了DAO 模式,
public interface CatalogDAO {
public Category getCategory(String categoryId, Locale locale) throws
CatalogDAOSysException;
public Product getProduct(String productId, Locale locale) throws
CatalogDAOSysException;
public Item getItem(String itemId, Locale locale) throws
CatalogDAOSysException;
}
2.1.4.11 CatalogWebImpl
客戶端直接,調(diào)用DAO,而不使用EJB,讀取產(chǎn)品信息
public class CatalogWebImpl implements java.io.Serializable {
protected CatalogDAO dao;
PetStore 中EJB 的設(shè)計模式
22/22
public CatalogWebImpl() {
try {
//獲得DAO 對象
dao = CatalogDAOFactory.getDAO();
} catch (CatalogDAOSysException se) {
throw new GeneralFailureException(se.getMessage());
}
}
public Category getCategory(String categoryId, Locale locale) {
try {
//使用DAO,獲得數(shù)據(jù),而不使用EJB
return dao.getCategory(categoryId, locale);
} catch (CatalogDAOSysException se) {
throw new GeneralFailureException(se.getMessage());
}
}
public Product getProduct(String productId, Locale locale) {
try {
//使用DAO,獲得數(shù)據(jù),而不使用EJB
return dao.getProduct(productId, locale);
} catch (CatalogDAOSysException se) {
throw new GeneralFailureException(se.getMessage());
}
}
public Item getItem(String itemId, Locale locale) {
try {
//使用DAO,獲得數(shù)據(jù),而不使用EJB
return dao.getItem(itemId, locale);
} catch (CatalogDAOSysException se) {
throw new GeneralFailureException(se.getMessage());
}
}
}
2.1.4.12 ProductListTag
定義一些TagLib 實現(xiàn)產(chǎn)品的列表,當(dāng)然使用了CatalogWebImp,實際就是DAO,顯示出產(chǎn)品
信息。
public class ProductListTag extends ListTag {
private String category = null;
PetStore 中EJB 的設(shè)計模式
23/23
private boolean hasNext = false;
protected void initParamPrefix() {
paramPrefix = "productList_" + category + "_";
}
protected Collection findCollection() throws Exception {
CatalogWebImpl catalog =
(CatalogWebImpl)
pageContext.getServletContext().getAttribute(WebKeys.CatalogModelKey);
if (catalog == null) {
return null;
}
Locale locale = JSPUtil.getLocale(pageContext.getSession());
ListChunk prodList = null;
Collection products = null;
// 獲得產(chǎn)品列表
prodList = catalog.getProducts(this.category, startIndex-1, numItems, locale);
products = prodList.getCollection();
if ((startIndex -1 + products.size()) < prodList.getTotalCount()) hasNext = true;
else hasNext = false;
return(products);
}
}
2.5. Page-by-Page Iterator 模式
在我們系統(tǒng)中一般有查詢,或者顯示信息列表。如在BBS 必須顯示貼之信息,但是我
們并不是一次把版面的所有貼之全部取出。因為我們一般不會把整個版都看,這樣每次要讀
到信息巨大,浪費了巨大的內(nèi)存。
2.5.1. 意圖
Efficiently access a large, remote list by retrieving its elements one
sublist of value objects at a time.
為了提高遠程,大數(shù)據(jù),而一次讀取值對象的部分對象。實際上就是不一次全部讀取,而是
每次讀取其中的一部分。不過在實際開發(fā)中,如果數(shù)據(jù)量不大,并且都要顯示應(yīng)該一次性讀
取,不要使用這種模式,具體數(shù)據(jù)量多大才使用,需要結(jié)合實際情況。
PetStore 中EJB 的設(shè)計模式
24/24
2.5.2. 動機
Distributed database applications often require users to consider a
long list of items, such as a catalog or a set of search results. In
these situations, presenting the entire list at once is often
unnecessary (the user isn‘t interested in all the items) or impossible
(there isn‘t enough space for all the items).
Furthermore, when retrieving a list of items, it would be very
expensive to use entity beans. One cost comes from using remote finder
methods to collect the requested beans; an additional, larger cost
comes from making remote calls to each bean to get data for the user.
These problems can be avoided by using a page-by-page iterator. Through
such an iterator, a client object can traverse a large list, one sublist
or page of value objects at a time; each page can be as big or as small
as the client desires. Consequently, the application uses fewer
resources to satisfy the client‘s immediate needs.
In the Java Pet Store application, the JSP page product.jsp displays only
a portion of an item list at any time, retrieving items from the
page-by-page iterator ProductItemListTag. When the client wants to see
the next or previous items in the list, product.jsp again calls on the
iterator to retrieve these items.
分布式數(shù)據(jù)庫的應(yīng)用經(jīng)常需要用戶考慮一長列數(shù)據(jù)項,例如一個目錄或一個搜索結(jié)果的集
合。在這些情況下,立刻提供全列的數(shù)據(jù)經(jīng)常不必要(用戶并不是對所有的數(shù)據(jù)項感興趣)
或不可能(沒有足夠的空間)。此外,當(dāng)重新獲得一列數(shù)據(jù)項時,使用Entity Bean 的代價
將非常高昂,一個開銷來自于使用遠程探測器來收集Requested Bean,另外,更大的開銷
來自對每個Bean 產(chǎn)生遠程調(diào)用以從用戶獲得數(shù)據(jù)。
通過Iterator,客戶機對象能一下子重新獲得一個子列或者頁的values Object,每一頁都
剛好滿足客戶機的需求,因此,程序使用較少的資源滿足了客戶機的立刻需求。
在Java Pet Store 這個例子中,JSP 頁面product.jsp 任何時候只顯示一個數(shù)據(jù)列的一部
分,從ProductItemListTag(Page-by-Page Iterator)重新獲得數(shù)據(jù)項,當(dāng)客戶機希望看
到列中的別的數(shù)據(jù)項,product.jsp 再次調(diào)用Iterator 重新獲得這些數(shù)據(jù)項,
PetStore 中EJB 的設(shè)計模式
25/25
2.5.3. 結(jié)構(gòu)
實際上在Java 中使用Collection,就實現(xiàn)了GoF 中Iteraror 模式,一般從數(shù)據(jù)庫中讀取數(shù)據(jù)
放入到Vector, , ArrayList 等中,然后就可義進行顯示。并且一般這種模式結(jié)合,
ValueObject,Fast_Lane Reader 模式。
2.5.4. PetStore 的例子
2.1.4.13 CatalogDAOImp
public class CatalogDAOImpl implements CatalogDAO {
//一次讀取部分數(shù)據(jù),開始值startIndex,總條數(shù)count
public ListChunk getProducts(String categoryId, int startIndex,
int count, Locale locale) throws CatalogDAOSysException {
int localCount = 0 ;
String qstr =
"select productid, name, descn " +
"from " +
DatabaseNames.getTableName(DatabaseNames.PRODUCT_TABLE, locale) +
" where category = " + "‘" + categoryId + "‘ " + " order by name";
Debug.println("Query String is:" + qstr);
int num =
getCount(DatabaseNames.getTableName(DatabaseNames.PRODUCT_TABLE,
locale) + " where category = " + "‘" + categoryId + "‘ ");
ArrayList al = new ArrayList();
Statement stmt = null;
ResultSet rs = null;
try {
getDBConnection();
stmt = dbConnection.createStatement();
PetStore 中EJB 的設(shè)計模式
26/26
rs = stmt.executeQuery(qstr);
HashMap table = new HashMap();
// skip initial rows as specified by the startIndex parameter.
while (startIndex-- > 0 && rs.next());
// Now get data as requested.
while (count-- > 0 && rs.next()) {
int i = 1;
String productid = rs.getString(i++).trim();
String name = rs.getString(i++).trim();
String descn = rs.getString(i++).trim();
Product product = null;
if (table.get(productid) == null) {
product = new Product(productid, name, descn);
table.put(productid, product);
al.add(product);
localCount++;
}
}
} catch(SQLException se) {
throw new CatalogDAOSysException("SQLException while getting " +
"multiple products for cat " + categoryId + " : " +
se.getMessage());
} finally {
closeResultSet(rs);
closeStatement(stmt);
closeConnection();
}
ListChunk rl = new ListChunk(num, al, startIndex, localCount);
return rl;
}
2.1.4.14 ProductItemListTag
public class ProductItemListTag extends ListTag {
protected Collection findCollection() {
CatalogWebImpl catalog =
(CatalogWebImpl)
pageContext.getServletContext().getAttribute(WebKeys.CatalogModelKey);
if (catalog == null) {
return null;
}
PetStore 中EJB 的設(shè)計模式
27/27
Locale locale = JSPUtil.getLocale(pageContext.getSession());
ListChunk itemList = null;
Collection items = null;
//進行讀取部分數(shù)據(jù)
itemList = catalog.getItems(productId, startIndex-1, numItems, locale);
items = itemList.getCollection();
if ((startIndex -1 + items.size()) < itemList.getTotalCount()) hasNext = true;
else hasNext = false;
return(items);
}
}
2.5.5. GOF 的Iterator 模式
意圖
提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內(nèi)部表示。
結(jié)構(gòu)
動機
• 訪問一個聚合對象的內(nèi)容而無需暴露它的內(nèi)部表示。
• 支持對聚合對象的多種遍歷。
• 為遍歷不同的聚合結(jié)構(gòu)提供一個統(tǒng)一的接口(即, 支持多態(tài)迭代)。
2.6. ServiceLocator 模式
這種模式在《J2EE 核心模式》有詳細描述,雖然在SUN 上沒有介紹,但在petstore1.3 版
本中使用了它。
PetStore 中EJB 的設(shè)計模式
28/28
2.6.1. 意圖
我們使用這種模式來抽取所有的JNDI 使用,并且隱藏了Context 的初始化,Ejb 對象的
LookUp,以及narrow。系統(tǒng)的所有客戶端使用統(tǒng)一代碼,來降低代碼的的復(fù)雜性,提供一
致控制,并且使用緩存提高性能。
2.6.2. 動機
抽取復(fù)雜性
通過封裝了查找,創(chuàng)建過程的復(fù)雜性,對系統(tǒng)的所有cilent,統(tǒng)一處理。
向客戶端提供統(tǒng)一的服務(wù)訪問
有利用添加新的業(yè)務(wù)組件
提高網(wǎng)絡(luò)性能
通過緩存提高性能
2.6.3. 結(jié)構(gòu)
PetStore 中EJB 的設(shè)計模式
29/29
2.6.4. PetStore 中的例子
2.1.4.15 ServiceLocatorImpl
public class ServiceLocatorImpl implements ServiceLocator, java.io.Serializable {
protected HttpSession session;
protected WebClientController wcc;
public ServiceLocatorImpl() { }
//定位ejb
public WebClientController getWebClientController() {
WebClientController wcc =
(WebClientController)session.getAttribute(WebKeys.WEB_CLIENT_CONTROLLER);
if ( wcc == null ) {
try {
InitialContext ic = new InitialContext();
String wccClassName = (String)
ic.lookup(JNDINames.WEB_CLIENT_CONTROLLER_IMPL);
wcc = (WebClientController)
Beans.instantiate(this.getClass().getClassLoader(), wccClassName);
wcc.init(session);
} catch (Exception exc) {
exc.printStackTrace();
throw new RuntimeException ("Cannot create bean of class
WebClientController");
}
session.setAttribute(WebKeys.WEB_CLIENT_CONTROLLER, wcc);
}
return wcc;
}
/**
*
* Create the WebClientController which in turn should create the
* EJBClientController.
*
*/
public void sessionCreated(HttpSessionEvent se) {
this.session = se.getSession();
wcc = getWebClientController();
this.session.setAttribute(WebKeys.SERVICE_LOCATOR, this);
PetStore 中EJB 的設(shè)計模式
30/30
}
/**
*
* Destroy the WebClientController which in turn should destroy the
* EJBClientController.
*
*/
public void sessionDestroyed(HttpSessionEvent se) {
if (wcc != null) wcc.destroy();
wcc = null;
}
}
2.1.4.16 我們項目的例子
當(dāng)初我們項目使用JB 開發(fā),EJB 服務(wù)器有的使用了BAS4.5 和WebLogic6。1,這樣EJB
定位,方法不一致,我們使用這種模式,這使用了GoF 中的Singleton 模式,這樣緩存context
提高了效率。不需要每次都要getInitialContext。這個代碼對大家應(yīng)該有用。
public class ServiceLocator {
private static ServiceLocator me;
Context context = null;
//系統(tǒng)服務(wù)器信息,如果改動只需,設(shè)置CURRENTSERVER
private static String WEBLOGICSERVER="weblogic6.1";
private static String BASSERVER="bas4.5";
private static String CURRENTSERVER="weblogic6.1";
//聯(lián)接EJB 服務(wù)器參數(shù)
private final static String EJBSERVERURL="t3://localhost:7001";
// AIX 服務(wù)器
//private final static String EJBSERVERURL="t3://192.168.4.25:7001";
//private final static String EJBUSERNAME="system";
//private final static String EJBPASSWORD="password";
//weblogic 的guest 用戶如果不刪除,可以使用null
private final static String EJBUSERNAME=null;
private final static String EJBPASSWORD=null;
PetStore 中EJB 的設(shè)計模式
31/31
/**
*初始化Context
* @return
* @throws Exception
*/
private Context getInitialContext() throws Exception {
String url = EJBSERVERURL;
String user =EJBUSERNAME;
String password =EJBPASSWORD;
Properties properties = null;
try {
//當(dāng)前服務(wù)器為Weblogic6.1 時
if(CURRENTSERVER.equals(WEBLOGICSERVER)){
properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
properties.put(Context.PROVIDER_URL, url);
if (user != null) {
properties.put(Context.SECURITY_PRINCIPAL, user);
properties.put(Context.SECURITY_CREDENTIALS, password == null ?
"" : password);
}
return new InitialContext(properties);
//當(dāng)前服務(wù)器為BAS 時
}else{
return new InitialContext();
}
}
catch(Exception e) {
e.printStackTrace();
System.out.println("Please make sure that the server is running.");
throw e;
}
}
private ServiceLocator() {
try {
context = getInitialContext();
} catch(Exception e) {
e.printStackTrace();
}
}
PetStore 中EJB 的設(shè)計模式
32/32
/**
*初始化ServiceLocator
* @return
*/
public static ServiceLocator getInstance() {
if (me == null) {
me = new ServiceLocator();
}
return me;
}
/**
*根據(jù)JNDI 名字,取得EJB Home
* @param name JDNI 名字
* @param clazz Home class 名字
* @return
*/
public EJBHome getHome(String name, Class clazz) {
try {
Object objref = context.lookup(name);
EJBHome home = (EJBHome)PortableRemoteObject.narrow(objref, clazz);
return home;
} catch(Exception e){
e.printStackTrace();
return null;
}
}
}
2.6.5. GOF 模式
2.1.4.17 Singleton 模式
實際在我們使用了這種模式,ServiceLocator 實例就使用這種模式,它只有一個實例,從而
保證只初始Context 一次,提高了效率
意圖
保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
適用性
當(dāng)類只能有一個實例而且客戶可以從一個眾所周知的訪問點訪問它時。
當(dāng)這個唯一實例應(yīng)該是通過子類化可擴展的,并且客戶應(yīng)該無需更改代碼就能使用一個
擴展的實例時。
PetStore 中EJB 的設(shè)計模式
33/33
結(jié)構(gòu)
2.7. Local 模式
2.7.1. 意圖
由于EJB 的效率低,如果部分EJB 僅是在內(nèi)部使用(同一個java VM,),而不是遠程調(diào)用,
就應(yīng)該使用本地方法。如果你看過PetStore 的EJB 層,就會發(fā)現(xiàn)大部分都使用Local 方法。
只有在提供Facde 的SessionBean 才使用遠程接口。這是在EJB2.0 才支持的,實際在我們
的項目中開始是第一次使用EJB2.0,并沒有使用本地方法,后來使用本地方法,具體效率
提高多少,我也不知道。其實在資料中一般不把它作為模式來講,但是我認為這是一種模式。
大家在自己的項目中最好使用它。據(jù)說在weblogic 7.0 的web 層與ejb 容器共享一個JVM,
所以可以使用本地方法,在兩層之間調(diào)用。
2.7.2. 動機
Local interfaces allow enterprise javabeans to work together within the same EJB container
using different semantics and execution contexts. The EJBs are usually co-located within the same
EJB container and ex ecute within the same Java Virtual Machine (JVM). This way, they do not
use the network to communicate and avoid the over-head of a Java Remote Method
Invocation-Internet Inter-ORB Protocol (RMI-IIOP) connection.
2.7.3. 結(jié)構(gòu)
結(jié)構(gòu)一般是,在遠程SessionBean 中調(diào)用本地接口EntityBean,結(jié)合Session Façade 模式。
PetStore 中EJB 的設(shè)計模式
34/34
ShoppingClientFacadeLocal
(f rom ejb)
AccountLocal
getStatus()
setStatus()
getCreditCard()
setCreditCard()
getContactInfo()
setContactInfo()
(f rom ejb)
CustomerLocal
getUserId()
getAccount()
getProfile()
(f rom ejb)
ShoppingClientFacadeLocalEJB,它是遠程方法,供遠程調(diào)用。
public class ShoppingClientFacadeLocalEJB implements SessionBean {
private ShoppingCartLocal cart = null;
private CustomerLocal customer = null;
/*
* Asume that the customer userId has been set
*/
//供遠程調(diào)用,內(nèi)部使用本地方法
public CustomerLocal getCustomer() throws FinderException {
try {
//使用本地調(diào)用,方法與遠程不同
InitialContext ic = new InitialContext();
Object o = ic.lookup("java:comp/env/ejb/local/Customer");
//獲得本地接口
CustomerLocalHome home =(CustomerLocalHome)o;
customer = home.findByPrimaryKey(userId);
} catch (javax.naming.NamingException nx) {
PetStore 中EJB 的設(shè)計模式
35/35
throw new GeneralFailureException("ShoppingClientFacade: failed to look up
name of customer: caught " + nx);
}
return customer;
}
}
2.7.4. PetStore 例子
在PetStore 中的EntityBean 都是使用的本地方法,在Session Facde 中調(diào)用本地接口。
見上面的例子。
2.8. CMR 模式
其實這也不算一種模式,它是在EJB2。0 中新增的重要特征。在IBM 的DevelpoerWorks
中有一篇教程介紹的非常詳細。在PetStore 的實體Bean 中,大量的使用了它。所以我把它
作為一種模式,重點介紹它。在JB6.0 中建立這種關(guān)系非常容易,如果自己手寫的話,需要
在web.xml 中增加關(guān)系。
2.8.1. 意圖
您不必編寫低級 JDBC 調(diào)用,并且不必編寫代碼來管理關(guān)系。它都內(nèi)建在 EJB 框架中。關(guān)系
的接口直接通過大多數(shù) EJB 開發(fā)者已經(jīng)很熟悉的流行的 java.util.Collection 和
java.util.Set 構(gòu)建。非??幔?br>2.8.2. 動機
使系統(tǒng)簡潔,方便開發(fā)。具體的好處需你仔細體會。
2.8.3. 結(jié)構(gòu)
實際就是建立我們的在數(shù)據(jù)庫中的關(guān)系。它包括1 對1,1 對多,多對多。我感覺最好大家
好好學(xué)習(xí)IBM 站點上的那篇文章。下圖是使用JB6.0 建立的關(guān)系。
PetStore 中EJB 的設(shè)計模式
36/36
2.8.4. PetStore 中的例子
在petStore 例子
public abstract class CustomerEJB implements javax.ejb.EntityBean {
private EntityContext context = null;
// getters and setters for CMP fields
// CMR Fields
public abstract AccountLocal getAccount();
public abstract void setAccount(AccountLocal account);
public abstract ProfileLocal getProfile();
public abstract void setProfile(ProfileLocal profile);
}
ejb.jar
<relationships>
<ejb-relation>
<ejb-relation-name>Customer-Account</ejb-relation-name>
<ejb-relationship-role>
PetStore 中EJB 的設(shè)計模式
37/37
<ejb-relationship-role-name>CustomerEJB</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>CustomerEJB</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>account</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>AccountEJB</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<cascade-delete />
<relationship-role-source>
<ejb-name>AccountEJB</ejb-name>
</relationship-role-source>
</ejb-relationship-role>
</ejb-relation>
<ejb-relation>
<ejb-relation-name>Customer-Profile</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>CustomerEJB</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>CustomerEJB</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>profile</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>ProfileEJB</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<cascade-delete />
<relationship-role-source>
<ejb-name>ProfileEJB</ejb-name>
</relationship-role-source>
</ejb-relationship-role>
</ejb-relation>
2.9. 業(yè)務(wù)代表模式
其實這種模式,就是GOF 的proxy 模式在ejb 中的應(yīng)用。在<<J2EE 核心模式>>一書有詳細
PetStore 中EJB 的設(shè)計模式
38/38
介紹。在petStore 的1.2.1 版本的例子很明顯
2.9.1. 意圖
使用業(yè)務(wù)代表來降低web 層和ejb 層之間的耦合,它隱藏了業(yè)務(wù)邏輯調(diào)用的細節(jié),如ejb
的查找和訪問的細節(jié)。其實客戶端,首先調(diào)用業(yè)務(wù)代表,然后由他負責(zé)真正在調(diào)用ejb 層的
服務(wù),就是proxy.。這種模式在GOF 中有詳細的介紹,在JIVE 項目使用的也比較多。
改模式一般結(jié)合Session Façade 和ServiceLocator 模式使用,通常它和Session Façade 模式
存在一對一的關(guān)系,是因為如果在業(yè)務(wù)代表存在調(diào)用多個ejb,那么就會把這些關(guān)系轉(zhuǎn)移到
session façade 中。
2.9.2. 動機
1. 降低web 層和ejb 層之間耦合
通過隱藏ejb 層的調(diào)用,如服務(wù)的查找等,由于只需要在業(yè)務(wù)代表一個地方進
行變化的管理和維護,所以實現(xiàn)起來更加容易。
2. 可以轉(zhuǎn)化ejb 層的異常
業(yè)務(wù)代表可以把ejb 層的異常,轉(zhuǎn)化會web 層的異常,如在petStore1.2.1 中的
例子把EstoreAppException 異常轉(zhuǎn)化為GeneralFailureException
public class ShoppingClientControllerWebImpl implements java.io.Serializable {
public synchronized ShoppingCart getShoppingCartEJB() {
try {
//com.sun.j2ee.blueprints.petstore.control.ejb.ShoppingClientController
sccEjb;
return sccEjb.getShoppingCart();
} catch (EStoreAppException ce) {
throw new GeneralFailureException(ce.getMessage());
} catch (RemoteException re) {
throw new GeneralFailureException(re.getMessage());
}
}
}
3. 實現(xiàn)失效恢復(fù)和線程同步
如果遇到ejb 層服務(wù)的失效,業(yè)務(wù)代表可以自動恢復(fù),而無需在調(diào)用處直接進
行恢復(fù),特別是在多處調(diào)用,每個處都需進行處理,而這樣可以集中在業(yè)務(wù)代
表處進行處理。
4. 向業(yè)務(wù)層提供更簡單的,統(tǒng)一的接口
5. 提高系統(tǒng)性能
業(yè)務(wù)代表可以向web 層提供請求的緩沖機制,提高性能。例如可以緩存遠程接
口,而不需每次都進行查找遠程接口。
PetStore 中EJB 的設(shè)計模式
39/39
6. 引入代理層
業(yè)務(wù)代表被看作是在web 層和wjb 層之間的代理層,從而引入了復(fù)雜性,降低
了靈活性。有些開發(fā)者,這樣增加了工作,同時它也帶來了某些好處。具體是
否使用改模式,請開發(fā)人員進行衡量。(我們的項目就沒有使用)
7. 隱藏遠程性
2.9.3. 結(jié)構(gòu)
2.9.4. PetStore 中的例子
在petStore1.2.1 中ShoppingClientControllerWebImpl 其實就是一個業(yè)務(wù)代表的例子。
public class ShoppingClientControllerWebImpl implements java.io.Serializable {
private com.sun.j2ee.blueprints.petstore.control.ejb.ShoppingClientController sccEjb;
private HttpSession session;
public ShoppingClientControllerWebImpl() {
}
/**
* constructor for an HTTP client.
* @param the HTTP session object for a client
*/
public ShoppingClientControllerWebImpl(HttpSession session) {
this.session = session;
ModelManager mm =
(ModelManager)session.getAttribute(WebKeys.ModelManagerKey);
PetStore 中EJB 的設(shè)計模式
40/40
sccEjb = mm.getSCCEJB();
}
public synchronized ShoppingCart getShoppingCartEJB() {
try {
return sccEjb.getShoppingCart();
} catch (EStoreAppException ce) {
throw new GeneralFailureException(ce.getMessage());
} catch (RemoteException re) {
throw new GeneralFailureException(re.getMessage());
}
}
public synchronized Customer getCustomerEJB() {
try {
return sccEjb.getCustomer();
} catch (EStoreAppException fe) {
throw new GeneralFailureException(fe.getMessage());
} catch (RemoteException re) {
throw new GeneralFailureException(re.getMessage());
}
}
public synchronized ProfileMgr getProfileMgrEJB() {
try {
return sccEjb.getProfileMgr();
} catch (EStoreAppException fe) {
throw new GeneralFailureException(fe.getMessage());
} catch (RemoteException re) {
throw new GeneralFailureException(re.getMessage());
}
}
public synchronized Collection handleEvent(EStoreEvent ese)
throws EStoreEventException {
try {
return sccEjb.handleEvent(ese);
} catch (RemoteException re) {
throw new GeneralFailureException(re.getMessage());
}
}
/**
* frees up all the resources associated with this controller and
PetStore 中EJB 的設(shè)計模式
41/41
* destroys itself.
*/
public synchronized void remove() {
// call ejb remove on self/shopping cart/etc.
try {
sccEjb.remove();
} catch(RemoveException re){
// ignore, after all its only a remove() call!
Debug.print(re);
} catch(RemoteException re){
// ignore, after all its only a remove() call!
Debug.print(re);
}
}
}
2.9.5. GOF 模式
2.1.4.18 Proxy 模式
意圖
為其他對象提供一種代理以控制對這個對象的訪問。
適用性
• 在需要用比較通用和復(fù)雜的對象指針代替簡單的指針的時候,使用P r o x y 模
式。下面是一 些可以使用P r o x y 模式常見情況:
1) 遠程代理(Remote Proxy )為一個對象在不同的地址空間提供局部代表。
NEXTSTEP[Add94] 使用N X P r o x y 類實現(xiàn)了這一目的。Coplien[Cop92] 稱這種
代理為“大使” (A m b a s s a d o r )。
2 )虛代理(Virtual Proxy )根據(jù)需要創(chuàng)建開銷很大的對象。在動機一節(jié)描述的I m a
g e P r o x y 就是這樣一種代理的例子。
3) 保護代理(Protection Proxy )控制對原始對象的訪問。保護代理用于對象應(yīng)該有
不同 的訪問權(quán)限的時候。例如,在C h o i c e s 操作系統(tǒng)[ C I R M 9 3 ]中K e m e l P
r o x i e s 為操作系統(tǒng)對象提供 了訪問保護。
4 )智能指引(Smart Reference )取代了簡單的指針,它在訪問對象時執(zhí)行一些附加
操作。 它的典型用途包括:
• 對指向?qū)嶋H對象的引用計數(shù),這樣當(dāng)該對象沒有引用時,可以自動釋放它(也稱為S
m a r tP o i n t e r s[ E d e 9 2 ] )。
• 當(dāng)?shù)谝淮我靡粋€持久對象時,將它裝入內(nèi)存。
• 在訪問一個實際對象前,檢查是否已經(jīng)鎖定了它,以確保其他對象不能改變它。
結(jié)構(gòu)
PetStore 中EJB 的設(shè)計模式
42/42
3. EJB 模式關(guān)系
正如Christopher Alexander 的評論,模式不是孤立存在的,需要其他模式的結(jié)合側(cè)更具
有偉力。現(xiàn)在我們討論以上所羅列各種模式之間的關(guān)系。
業(yè)務(wù)代表
Session Facade
ServiceLocator
值對象組裝器
Page-by-Page
Iterator
復(fù)合實體模式Value Object模式
CRM模式Local模式DAO模式
Fast-
Lane
Reader
模式
首先是在web 層與ejb 層的結(jié)合層(Proxy)由業(yè)務(wù)代表實現(xiàn),它一般與SessionFacade
是一對一的關(guān)系,當(dāng)然它一般會使用ServiceLocator 模式,來查找和定位ejb??蛻舳艘话?br>使用業(yè)務(wù)代表來調(diào)用業(yè)務(wù)邏輯,而不是直接進行調(diào)用。為了簡化接口,我們使用SessionFacade
模式,來封裝復(fù)雜的業(yè)務(wù)邏輯,通過SessionFacade 模式來調(diào)用其他的ejb,一般其他被調(diào)用
者,一般使用CRM 和Local 模式,這樣可以提高效率。為了提高接口的粗粒度,我們一般
使用Value Object 模式,復(fù)合實體,以及值對象組裝器模式。有時接口的需要值對象的列表,
我們又使用Page-By-Page 模式,來緩存大量的之對象。還有一種景況,就是為了提高效率,
不使用ejb,而是直接連接數(shù)據(jù)庫,就是Fast-Lane-Reader。
• 業(yè)務(wù)代表模式
• ServiceLocator 模式
• SessionFacade 模式
PetStore 中EJB 的設(shè)計模式
43/43
• Value Object 模式
• Page-By-Page 模式
• 復(fù)合實體
• CRM 模式
•
4. 相關(guān)的資料
1. sun 站點
2. IBM DevelpoerWorks
3. 《J2EE 模式》
4. 《設(shè)計模式-可復(fù)用面向?qū)ο蟮能浖幕A(chǔ)》
5.
www.javaunion.org www.chinajavaworld.com 站點的一些網(wǎng)友作品。
5. 總結(jié)
本人把自己對petStore 中的ejb 設(shè)計模式進行了初步總結(jié),并且參考了許多文章(有好多
直接抄過來),初步寫出,定義為1.0 版本。希望與大家討論,逐漸完善。