1. 程式人生 > >EJB:快速入門

EJB:快速入門

man gpo logic socket通信 pub 說明 失去 動態 服務端

  • 1、EJB概念
  • 2、EJB體系結構
  • 3、SessionBean
    • 3.1 SessionBean 服務端組件
    • 3.2 Remote 與 Local 模式
    • 3.3 Client訪問處理流程
      • 3.3.1 Remote模式下的SessionBean處理流程
      • 3.3.2 Local 模式下的SessionBean處理流程
    • 3.4 基於EJB2.1的Demo
    • 3.5 SessionBean分類
      • 3.5.1 Stateful
      • 3.5.2 Stateless
      • 3.5.3 Singleton
    • 3.6 SessionBean生命周期
      • 3.6.1 Stateful
      • 3.6.2 Stateless
      • 3.6.3 Singleton
  • 4、EntityBean
  • 5、MessageDrivenBean
  • 6、EJB vs Spring

1、EJB 概念

EJB是Enterprise Java Bean的簡稱,翻譯後應該是:企業級Java組件,也可以稱為分布式組件。它是為分布式商業服務提供了一個思想超前的、提供了安全和事務的、通用的平臺。

2、EJB體系結構

EnterpriseBean和Serializable接口一樣,是一個標記性接口。用於標記一個類為一個Bean(豆,組件)。它有三種實現:SessionBean,EntityBean,MessageDrivenBean。

SessionBean:它是對業務邏輯的封裝,類似於我們經常寫的Service層。它可以以local, remote, webservice 服務的方式被client調用。

EntityBean:它是對數據庫對象的封裝,一個EntityBean,就是數據庫的一條記錄。

MessageDrivenBean:一個messageDrivenBean其實就是一個javax.jms.MessageListener。在JMS中有MessageConsumer,它支持兩種接收消息的方式:同步接收采用MessageConsumer#receive()方法,異步接收則是為MessageConsumer設置一個MessageListener,一旦接收到消息,就調用listener#onMessage()。

3、SessionBean

它是對業務邏輯的封裝,類似於我們經常寫的Service層。它可以以local, remote, webservice 服務的方式被client調用。

3.1 SessionBean服務端組件

SessionBean服務端有三大組件Home、EJbObject、SessionBean。

SessionBean是我們編寫業務邏輯的地方。譬如數據庫操作,進行計算等等。但是它對於客戶端是不可見的,一個SessionBean實例的創建、銷毀、激活、鈍化等都是由EJB容器來管理的。

EJBObject:你可以將EJBObject看作是SessionBean對象的Proxy。需要將你的業務方法同樣在EJBObject中復制一份。例如有一個HelloSessionBean#sayHello(str) 業務,如果要將該業務方法暴露出去給Client使用,與之對應的HelloEJBObject中必然得包含#sayHello(str)方法。也就是說Client需要使用EJBObject來達到與SessionBean交互的。

Home:這個名字起的怪異,我們可以將其理解為一個SessionBean的Factory。EJB容器通過Home對象來創建SessionBean對象,並裝配出它的代理對象(EJBObject對象)。這是它的唯一用途。

3.2 Remote與Local

對於Home,和EJBObject,它們倆個都分為兩類:Remote,Local。

Remote模式的,主要用於不在同一個JVM進程裏,而在同一個進程裏使用時,只需要使用Local模式的即可,這樣選擇自然是為了性能考慮。

Home、EJBObject我們看到的只是接口,誰來創建他們呢?

這個問題其實很簡單了,之前已說了EJBObject是一個Proxy,我們不難想到,基於動態代理或者字節碼技術,就可以動態的(具體來說就是部署EJB時)生成Home、EJBObject的實現類。

此外,在構建完Home的實現類之後,就會創建出一個單例的Home對象,並將其註冊到JNDI服務器上。這樣客戶端就可以通過jndi服務lookup到該Home的引用。

EJBObject對象,是在client通過EJBHome#create() 或者EJBLocalHome#create()時由服務端的Home對象創建一個EJBObject的實例,並返回它的引用給客戶端。

3.3 Client訪問處理流程

在上面已經說明Home對象在ejb應用部署時就會創建出一個單例,並註冊到JNDI服務器上。

客戶端訪問一個業務的流程是怎樣的呢?

3.3.1 Remote模式下SessionBean 的訪問流程

1、客戶端通過JNDI獲取到Home對象(EJBHome)的引用

2、客戶端使用homeRef#create()方法來創建出EJBObject的Stub。

2.1)客戶端底層使用Socket通信將次過程發給服務端Skeleton。

2.2)Skeleton調用服務端的Home對象的create方法,分配SessionBean對象(可能是新創建一個,也可能是從對象池中取一個,具體怎樣依賴於是否是Stateful的),同時為該SessionBean對象生成一個代理對象(EJBObject實例),然後返回代理對象的引用

2.3)客戶端拿到EJBObject的引用就是Stub對象。

3、客戶端訪問業務

3.1) 客戶端底層使用Socket通信將次過程發給服務端Skeleton。

3.2)Skeleton根據請求找到該EJBObject,調用與之關聯的SessionBean的相應的業務。返回結果

3.3)客戶端得到調用結果

3.3.2 Local模型下SessionBean的訪問流程

1、客戶端通過JNDI獲取到Home對象(EJBLocalHome)的引用

2、客戶端使用homeRef#create()方法來創建出EJBLocalObject(怎麽創建也要依賴於是否的Stateful的)

3、客戶端訪問業務

很容易對比出Local模式性能好在哪了。

在EJB3 中,會有更方便的寫法了,用@EJB即可搞定。

3.4 基於EJB2.1的Demo

技術分享圖片

1)編寫業務接口 AdviceService

public interface AdviceService {
    String getAdvice(String str) throws RemoteException;
}

2) 編寫SessionBean類

public class AdviceServiceImpl implements AdviceService, SessionBean {
     public String getAdvice(String str){
         return “Advice” + str;
}
// 其他的ejbCreate,ejbActivate等不展示
}

3)指定EJBObject接口

public interface AdviceServiceEjbObject extends EJBObject, AdviceService{
}

4) 指定Home接口

public interface AdviceServiceFactory extends EJBHome{
    public AdviceServiceEjbObject create() throws RemoteException, CreateException;
}

5) 在ejb-jar.xml中配置要暴漏的SessionBean:

技術分享圖片

ejb-jar.xml是放在META-INF目錄下。

6)關聯到jndi服務

技術分享圖片

這一步是WebLogic服務器上配置的,其他的JavaEE服務器應該也有類似的機制。

7)打包部署到JavaEE服務上。

8)客戶端調用

技術分享圖片

代碼中的JndiResources.getProperty(“ejb.advice”) 用於取得 xxx.properties文件中配置的JNDI名稱,這個JNDI名稱,就是第6步映射的JNDI名稱。EjbEnvs.getEjbEnv()方法,是為了得到在不同的JavaEE服務器上的InitialContext的配置,這屬於測試用例的配置。

例如:

技術分享圖片

然後就是通過JNDI獲取的Home Reference,然後調用create獲取EJBObject的Stub,最後調用業務方法。

3.5 SessionBean 分類

在上面說的通過Home對象的create過程中,有個SessionBean創建,是要依賴於是否是Stateful的。也就是說SessionBean會區分為:Stateless, Stateful,在EJB3.1加入Singleton的。

3.5.1 Stateful SessionBean

對於一個普通的Java對象而言,它的屬性就是它的狀態。而Stateful SessionBean是與Client相關聯的,也就是說一個Client會有一個SessionBean與之對應。這樣的SessionBean可以存活在與Client的整個會話期間。當一個Client終端時,SessionBean才會與該Client失去聯系。

SessionBean的state(也就是對象的字段)會在整個會話期間保留,直到會話關閉。

3.5.2 Stateless SessionBean

無狀態的SessionBean,它的state只會存在於業務方法調用期間,一旦方法調用完畢,這些字段就會失效。無狀態的SessionBean不會與某個Client關聯。

3.5.3 Singleton SessionBean

單例的SessionBean,那麽對於一個應用,只會存在一個這樣的對象。它是可以被多個Client並發的調用的。Stateful、Stateless SessionBean,在同一時間都只能為一個Client服務,它們是采用對象池技術實現的。

Stateful

Stateless

Singleton

與Client關聯

單個實例支持並發訪問

對象管理

LRU等緩存

對象池

單例

發布為WebService

存活周期

整個會話

單個業務方法調用

應用

單個實例被多個Client重用

不會

可以

可以

3.6 SessionBean 生命周期

3.6.1 Stateful SessionBean

對於Stateful SessionBean。當Client通過Home Ref執行create時,服務端的Home會直接創建一個代理對象(EJBObject/EJBLocalObject實例),和一個SessionBean(會被EJB容器決定是否作為鈍化狀態)。

技術分享圖片

圖中上邊的:1)2)3)4)分別代表了:

1) SessionBean 對象的創建

2) 依賴註入

3) 執行@PostConstruct

4) 執行init方法、或者ejbCreate方法。

此時對象創建完畢,bean變為ready狀態,也會返回給client一個proxy的stub。但EJB容器仍然要對這個SessionBean的狀態定期進行處理,通常會基於LRU緩存對cache中bean進行passivate處理。Passivate之前、activate之後會有相應的回調方法執行。

圖中下邊的1)2)代表了:

1) Client調用@Remove

2) 服務端調用@PreDestory

之後一個SessionBean就被銷毀了,等待它的將是JVM的GC。

3.6.2 Stateless SessionBean

對於Stateless SessionBean,當Client使用Home Ref創建EJBObject(或者EJBLocalObject)對象時,並不會創建一個關聯的Session Bean。當調用業務時,才會從SessionBean Pool選擇一個空閑的處理業務。它是不存在passivate, activate的轉換的。

技術分享圖片

3.6.3 Singleton SessionBean

上文說了,它的生命周期在整個應用期間。

技術分享圖片

4、EntityBean

可以把EntityBean看做是數據庫記錄。數據庫的訪問才用JPA(Java Persistence Abstract,參見javax.persistence.*)

分為CMP(Container managed Persistence),BMP (Stateless SessionBean managed Persistence)兩種,他們支持事務(聲明式事務、編程式事務)

事務支持扁平式事務,嵌套式事務。學過Spring的人應該都了解的,相信Spring的作者肯定對EJB了解極深。

5、MessageDrivenBean

在前面已經說明,他就是一個MessageListener。

技術分享圖片

前文已經說明了一切。這裏只說一下MessageDrivenBean的生命周期:

技術分享圖片

6、EJB vs Spring

網上充斥著大量的EJB已死、Spring替代EJB的文章。我就納悶了,EJB是做分布式業務調用的,Spring是做IOC的,兩者有什麽可比的呢?這是我在了解EJB之前的一個疑問。

通過對EJB做了個簡單的了解,我終於知道他們在比什麽了:

AOP & IOC

通過上面對EJB的闡述,我們從Bean的生命周期中,我們可以看到,EJB容器可以說是IOC的先驅。在後續的版本中EJB已經補齊了IOC的支持。

EJB中對SessionBean調用之前,還有做一些其他事情, 譬如Security、Transaction。這完完全全就是AOP的應用嘛。

通過上面的例子知道,要部署一個EJB組件,確實挺麻煩的,還要寫那麽多程序化的接口(Home和EJBObject)。EJB3.0之後支持了註解,釋放了這個繁瑣的過程。也就是說EJB的笨重,應該是Spring等一大批IOC容器(Spring,Guice,HK2)產生的原因了。

只能說EJB在某些場合(Local模式下)下被Spring替代。

EJB:快速入門