什么是java ejb
在開發(fā)分布式系統(tǒng)時(shí), 采用ejb可以使得開發(fā)商業(yè)應(yīng)用系統(tǒng)變得容易, 應(yīng)用系統(tǒng)可以在一個(gè)支持ejb的環(huán)境中開發(fā), 開發(fā)完之后部署在其它的ejb環(huán)境中, 隨著需求的改變, 應(yīng)用系統(tǒng)可以不加修改地遷移到其它功能更強(qiáng)、更復(fù)雜的服務(wù)器上。ejb在系統(tǒng)實(shí)現(xiàn)業(yè)務(wù)邏輯層里面負(fù)責(zé)表示程序的邏輯和提供訪問數(shù)據(jù)庫的接口。
1. ejb歷史
1.1 從擁抱到拋棄
由于ibm和sun microsystems等ejb提倡者力推其前景,起初一些大公司紛紛采用ejb部署他們的系統(tǒng)。然而隨后各種問題便接踵而至,對(duì)ejb的惡評(píng)短時(shí)間內(nèi)激增。對(duì)于初學(xué)者,ejb的api顯得太過困難;對(duì)于許多程序員來說,書寫那些必須拋出特定異常的接口并將bean類作為抽象類實(shí)現(xiàn)的做法既不直觀也不正常。當(dāng)然,ejb所被賦予的使命,如對(duì)象關(guān)系映射和事務(wù)管理確實(shí)有其天然復(fù)雜性,但其api之復(fù)雜還是令開發(fā)人員們覺得望而卻步,一些人開始懷疑ejb除了引入了復(fù)雜的實(shí)現(xiàn)手段以外似乎并未帶來什么實(shí)際好處。
另外,實(shí)際運(yùn)用中被發(fā)現(xiàn),如果使用ejb來封裝業(yè)務(wù)邏輯會(huì)帶來性能上的下降。這是因?yàn)?,最早的ejb規(guī)范只允許客戶端通過特定協(xié)議(如corba)進(jìn)行遠(yuǎn)程方法調(diào)用來調(diào)用,即使大部分實(shí)際應(yīng)用根本就不需要分布式計(jì)算。直到ejb 2.0才引入了本地接口,以支持可以開發(fā)不通過網(wǎng)絡(luò)就能直接本地調(diào)用的ejb系統(tǒng)。
盡管如此,ejb的廣泛普及仍然為其復(fù)雜度所制約。盡管已經(jīng)有一些高質(zhì)量的集成開發(fā)工具可以協(xié)助開發(fā)人員通過自動(dòng)編碼解決一部分重復(fù)作業(yè),但這并不能降低學(xué)習(xí)此項(xiàng)技術(shù)的難度。另一方面,“草根階層”的編程愛好者們發(fā)起了一場(chǎng)旨在使用 “輕量級(jí)”技術(shù)以代替復(fù)雜的ejb的運(yùn)動(dòng)。這些技術(shù)包括hibernate(用于提供數(shù)據(jù)持久化和對(duì)象-關(guān)系映射)及spring框架(用于封裝業(yè)務(wù)邏輯)。盡管它們不像ejb那樣有巨頭支持,但其在庶民間卻更加流行,并且也被一些對(duì)ejb深感失望的企業(yè)所采用。
1.2 重生
ejb規(guī)范起初的一個(gè)主要價(jià)值—對(duì)分布式應(yīng)用進(jìn)行事務(wù)管理—在隨后的實(shí)踐中被一致認(rèn)為幾乎沒能派上用場(chǎng)。
對(duì)于企業(yè)級(jí)應(yīng)用來說,spring和hibernate等簡化框架更加實(shí)用。因此,ejb 3.0規(guī)范(jsr 220)為了迎合這個(gè)趨勢(shì)相比于其前輩進(jìn)行了一次激進(jìn)的大跳躍。受到spring 影響,ejb 3.0也使用所謂的“傳統(tǒng)簡單java對(duì)象(pojo)”;同時(shí),支持依賴注入來簡化全異系統(tǒng)的集成與配置。
hibernate的創(chuàng)始人gavin king參與了這一新版規(guī)范的制訂,并對(duì)ejb大加提倡。hibernate的許多特性也被引入到j(luò)ava持久化api當(dāng)中,從而取代原來的實(shí)體bean。
ejb 3.0規(guī)范大幅采用java注釋(annotation)來對(duì)代碼進(jìn)行元數(shù)據(jù)修飾,從而消減了此前ejb編程的冗雜性。
相應(yīng)地,ejb 3.0幾乎成為了一個(gè)全新的api,與此前的數(shù)版可謂毫無相似度可言 。
2. 技術(shù)特點(diǎn)
1) 具有可復(fù)制性。由于ejb是以組件為基礎(chǔ)的技術(shù)模型, 所以在任何一個(gè)ejb服務(wù)器中都可以隨意部署, 或者將其他模式直接進(jìn)行移植和復(fù)制, 不需要定制專用的ejb服務(wù)器系統(tǒng)和容器。ejb之所以能夠被復(fù)制, 是因?yàn)樽屪陨淼姆?wù)器已經(jīng)定義了一些規(guī)范服務(wù), 而這些服務(wù)又可以對(duì)ejb容器和組件之間的關(guān)系進(jìn)行定義, 即使進(jìn)行復(fù)制也不會(huì)破壞其內(nèi)部結(jié)構(gòu)的穩(wěn)定性。
2) 具有重復(fù)性特點(diǎn)。因?yàn)閑jb是服務(wù)器上運(yùn)行程序的一個(gè)功能片段, 可以進(jìn)行重新組裝和重新定義, 所以它能夠利用自身的這一特性和其他組間一起組建出符合使用需求的應(yīng)用系統(tǒng), 而且可以同時(shí)為多個(gè)系統(tǒng)提供服務(wù)。
3) 具有獨(dú)立的平臺(tái)。和計(jì)算機(jī)網(wǎng)絡(luò)中任何一個(gè)特殊平臺(tái)、internet協(xié)議和中間件或其他基礎(chǔ)設(shè)施不同, ejb結(jié)構(gòu)平臺(tái)完全是獨(dú)立的, 具有極強(qiáng)的獨(dú)立性。也正是因?yàn)槿绱? 它所開發(fā)出來的應(yīng)用程序才能不進(jìn)行任何修改, 完全被復(fù)制到另外的平臺(tái)中。
4) 具有廣闊的拓展空間。ejb模型是以多層分布式體系結(jié)構(gòu)為基礎(chǔ)構(gòu)建起來的, 因?yàn)樵撓到y(tǒng)的多功能, 所以不管是規(guī)模較小的應(yīng)用程序, 還是規(guī)模較大的事務(wù)處理, 都可以運(yùn)用高模型。隨著電子信息和通信技術(shù)的不斷發(fā)展, 應(yīng)用程序的需求量不斷增加, 為了讓這些應(yīng)用程序可以在不改變核心程序的前提下被復(fù)制到操作功能更強(qiáng)大、運(yùn)行環(huán)境更先進(jìn)的系統(tǒng)中, 就可以運(yùn)用ejb模型來實(shí)現(xiàn)。所以, ejb具有極強(qiáng)的擴(kuò)展性, 而且電子技術(shù)的進(jìn)步會(huì)為它的應(yīng)用提供一個(gè)非常廣闊的空間。
3. ejb組件的體系架構(gòu)
ejb的架構(gòu)主要包括以下幾方面:
1) enterprise java bean類:包含了組件的實(shí)現(xiàn)細(xì)節(jié), 是實(shí)際完成bean功能的地方。ejb容器根據(jù)需要調(diào)用這個(gè)類對(duì)bean進(jìn)行實(shí)例化。
2) ejb對(duì)象:在服務(wù)器端, 一個(gè)ejb對(duì)象是一個(gè)實(shí)現(xiàn)了bean的遠(yuǎn)程接口 (具有網(wǎng)絡(luò)功能) 的分布式對(duì)象, 它在服務(wù)器端上包裝了bean的實(shí)例。ejb對(duì)象由容器控制在適當(dāng)?shù)臅r(shí)機(jī)調(diào)用所需的服務(wù), 這些服務(wù)對(duì)客戶而言是透明的。
3) remote接口:遵照ejb規(guī)范, 所有的remote接口都必須來源于一個(gè)通用的接口, 包含了ejb對(duì)象必須實(shí)現(xiàn)的方法。
4) home接口:開發(fā)者必須定義home接口, 容器廠商則提供從home接口中產(chǎn)生home對(duì)象實(shí)現(xiàn)的方法。
4. ejb組件的工作流程
ejb component在部署到應(yīng)用服務(wù)器上之后, 客戶端就可以調(diào)用它來完成各種功能。工作過程如下:
1) 客戶端首先通過jndi服務(wù)檢索home對(duì)象。在ejb應(yīng)用部署到應(yīng)用服務(wù)器上之后, 容器會(huì)自動(dòng)獲得home對(duì)象的信息并將其加入到j(luò)ndi中。
2) jndi服務(wù)返回所查找的home對(duì)象的引用。
3) home對(duì)象的創(chuàng)建或者查找ejb對(duì)象。
4) home對(duì)象將獲得的ejb對(duì)象返回給客戶端。
5) 客戶端利用獲得的ejb對(duì)象引用, 調(diào)用業(yè)務(wù)方法。
6) ejb對(duì)象獲得對(duì)應(yīng)bean的一個(gè)實(shí)例并將相應(yīng)的業(yè)務(wù)方法調(diào)用傳遞給該實(shí)例。
7) bean實(shí)例通過其實(shí)現(xiàn)代碼, 完成相應(yīng)的業(yè)務(wù)邏輯并將結(jié)果返回給ejb對(duì)象。
8) ejb對(duì)象將方法的結(jié)果返回給客戶端。
5. ejb種類
ejb容器可以接受三類ejb
- 會(huì)話bean(session beans)
- 無狀態(tài)會(huì)話bean(stateless session beans)
- 有狀態(tài)會(huì)話bean(stateful session beans)
- 實(shí)體bean(entity beans)
- 消息驅(qū)動(dòng)bean(message driven beans ,mdbs)
無狀態(tài)會(huì)話bean是一類不包含狀態(tài)信息的分布式對(duì)象,允許來自數(shù)個(gè)客戶端的并發(fā)訪問。實(shí)例變量的內(nèi)容在前后數(shù)次呼出中不被保留(確切地說是不保證保留)。由于不必控制與用戶間的對(duì)話信息而減少了開銷,無狀態(tài)會(huì)話bean不像有狀態(tài)會(huì)話bean那樣具有資源集約性。舉例來說,一個(gè)發(fā)送郵件的ejb就可被設(shè)計(jì)為一個(gè)無狀態(tài)會(huì)話bean。在整個(gè)會(huì)話期,用戶只向服務(wù)器提交一個(gè)動(dòng)作:發(fā)送指定郵件到指定地址。(稱為開關(guān)行為)
有狀態(tài)會(huì)話bean是包含狀態(tài)的分布式對(duì)象,即是說,貫穿整個(gè)會(huì)話它們都要保有客戶端信息。舉例而言,在一個(gè)網(wǎng)上商店進(jìn)行實(shí)施結(jié)賬很可能就需要一個(gè)有狀態(tài)會(huì)話bean,因?yàn)榻Y(jié)賬是一個(gè)多步動(dòng)作,服務(wù)器端必須可以隨時(shí)了解到用戶已經(jīng)進(jìn)行到了哪一步。此外,盡管有狀態(tài)會(huì)話bean的狀態(tài)信息可被保持,但始終只能是由同一個(gè)用戶來訪問之。
實(shí)體bean是含有持久化狀態(tài)的分布式對(duì)象。這個(gè)持久化狀態(tài)的管理既可以交給bean自身(bean-managed persistence,bmp),也可以托付于外部機(jī)制(container-managed persistence,cmp)。
消息驅(qū)動(dòng)bean是支持異步行為的分布式對(duì)象。它們并不對(duì)請(qǐng)求進(jìn)行當(dāng)即響應(yīng)。比方說,某網(wǎng)站用戶點(diǎn)擊“請(qǐng)通知我更新信息”按鈕,將會(huì)觸發(fā)某個(gè)mdb將這名用戶加入到數(shù)據(jù)庫的希望獲得更新信息用戶列表中。這個(gè)動(dòng)作就是一個(gè)異步的消息驅(qū)動(dòng)過程,因?yàn)橛脩舨槐氐却?dāng)時(shí)會(huì)返回某個(gè)結(jié)果。mdb的消息源來自java消息服務(wù)(jms)提供的消息隊(duì)列或消息主題。自ejb 2.0規(guī)范起,jms被加入進(jìn)來以允許在容器內(nèi)部實(shí)施事件驅(qū)動(dòng)處理。與其他ejb不同,mdb不存在一個(gè)用戶視圖(如需要用戶引用的遠(yuǎn)程接口),用戶也不能通過資源定位獲得一個(gè)mdb實(shí)例。mdb只在后臺(tái)監(jiān)聽消息源并實(shí)施自動(dòng)處理。
除了上述以外,當(dāng)前還有一些ejb處于設(shè)想階段,如jsr 86提出了用于在java ee應(yīng)用中集成多媒體對(duì)象的媒體bean(enterprise media beans)。
6. ejb實(shí)行
ejb部署于應(yīng)用服務(wù)器端的ejb容器中。規(guī)范給定了ejb與ejb容器之間,以及用戶代碼與ejb/ejb容器之間的交互方式。對(duì)于java ee api,javax.ejb包定義了ejb類,javax.ejb.spi包定義了ejb容器應(yīng)當(dāng)實(shí)現(xiàn)的各個(gè)接口。
在ejb 2.1和以前的版本中,每個(gè)ejb都由一個(gè)類和兩個(gè)接口組成。ejb容器負(fù)責(zé)創(chuàng)建這個(gè)類的實(shí)例,接口則供客戶端調(diào)用。
兩個(gè)接口分別被稱為home接口和組件接口,負(fù)責(zé)提供各個(gè)ejb遠(yuǎn)程方法聲明。這些ejb遠(yuǎn)程方法可分成兩組:
- 類方法:由home接口提供。與特定實(shí)例無關(guān),僅負(fù)責(zé)一些公共內(nèi)容,比如創(chuàng)建一個(gè)新的ejb實(shí)例(create方法),或?qū)ふ乙粋€(gè)已經(jīng)存在的ejb實(shí)例(find方法)等等。
- 接口方法:由組件接口提供的針對(duì)特定實(shí)例的業(yè)務(wù)方法。
ejb容器將為這些接口提供對(duì)應(yīng)的實(shí)現(xiàn)類以充當(dāng)客戶遠(yuǎn)程代理,當(dāng)客戶端調(diào)用這個(gè)生成的代理類的某個(gè)方法時(shí),代理類內(nèi)部會(huì)將此調(diào)用的方法和參數(shù)封裝成一個(gè)消息發(fā)送給服務(wù)器。服務(wù)器收到消息后在轉(zhuǎn)發(fā)給真實(shí)的ejb實(shí)例,后者負(fù)責(zé)執(zhí)行真正的業(yè)務(wù)邏輯。
6.1 遠(yuǎn)程通信
ejb規(guī)范要求ejb容器能夠支持基于rmi-iiop的ejb訪問。ejb既可被任何corba應(yīng)用訪問,也能提供web服務(wù)。
6.2 事務(wù)
ejb容器必須支持符合acid(原子性/一致性/獨(dú)立性/持久性)特性的容器級(jí)事務(wù)管理,以及bean內(nèi)部事務(wù)管理。容器級(jí)事務(wù)需在部署描述符中(ejb應(yīng)用的配置文件)進(jìn)行聲明。
6.3 事件
ejb使用jms向客戶對(duì)象發(fā)送消息,客戶則可以異步地接受這些消息。mdb則接受來自客戶端的消息。
6.4 命名和目錄服務(wù)
ejb客戶端使用jndi或corba名字服務(wù)定位home接口實(shí)現(xiàn) 對(duì)象。通過此home接口,用戶還可以尋找,創(chuàng)建或刪除實(shí)體對(duì)象。
6.5 安全
ejb容器對(duì)客戶端的訪問權(quán)限負(fù)責(zé)。
6.6 部署ejb
ejb規(guī)范還定義了一個(gè)跨平臺(tái)的統(tǒng)一部署機(jī)制。部署描述符中定義了關(guān)于ejb應(yīng)用的一切相關(guān)內(nèi)容。文件名通常為ejb-jar.xml。
部署描述符是一個(gè)xml文檔,負(fù)責(zé)為該ejb應(yīng)用中的每一個(gè)ejb定義入口。部署描述符的主要內(nèi)容包括:
- home接口名
- bean的java類名
- home接口的java接口名
- 組件接口的java接口名
- 持久化存儲(chǔ)(針對(duì)實(shí)體bean)
- 安全策略和角色分配
通常ejb容器提供者還定義了一些額外的xml或其他格式描述文件來強(qiáng)化其容器的功能。他們還同時(shí)提供這些描述文件的解讀工具類和對(duì)home接口的自動(dòng)實(shí)現(xiàn)類生成。
ejb3.0起開始廣泛使用java注釋替代傳統(tǒng)的部署描述符ejb-jar.xml。但后者仍然有效。