基於訊息Bean的EJB非同步通訊
Bromon原創 請尊重著作權
非同步通訊是一個提升程式執行效率的很重要的手段,而效能問題又是EJB誕生以來一直都很受關注的話題。EJB執行效率不高的原因是用戶端需要查詢和調用遠程介面,而本身在處理資料是很快的,畢竟EJB有比較完善的緩衝機制,幾十萬的app server也不是白吃記憶體的。用戶端程式如果能夠採用非同步通訊,只負責以訊息的形式發送請求和需要處理的資料,不用等待系統查詢、調用遠程介面,可以節省大量時間,這也是EJB 2.0中引入訊息驅動Bean的一個重要原因。J2EE的訊息機制允許你以訊息的形式傳遞對象,我們可以利用它實現很多應用。
在最近正在寫的一個考試系統中,系統把學生對每一個題目的回答都即時記錄到資料庫,這樣做會有比較頻繁的資料庫操作,對效能有比較大的影響,但是可以讓學生的每一次答題都得到永久性儲存,避免因為意外死機或異常退出造成學生提交的答案丟失。毫無疑問,資料的安全可靠是第一位的,但是上百個學生並行作業,這個負載也是很巨大的。為了在穩定和效能上謀求平衡,我們考慮這樣一種模型:
◆在伺服器端建立一個永久性的隊列,該隊列可以保證資料安全,即使伺服器意外重啟,裡面的對象也不丟失。並且有一種機制保證隊列中的對象只會被處理一次。
◆用戶端把答案資料封裝成javabean,然後提交到這個隊列中,提交之後不必等待資料處理完成,直接進行以後的操作,產生新的資料後繼續往隊列裡存放,不必去關心資料什麼時候會被處理。
◆伺服器以FIFO的順序處理隊列中的資料包。
結構大致如:
?
很明顯,這裡只提供一種單向通訊,但是並非被迫,完全可以在建立另外一個隊列,存放返回的訊息,對應的訊息通過訊息ID進行關聯。以訊息bean為核心的javaMessage Service(JMS)實際上就是這樣一個架構。
首先設計一個操作答案資料表的類:
?
它包含增加答案的方法和修改已有答案的方法,在實際的項目中,它由一個映射資料表的CMP Entity Bean和一個封裝程式邏輯的SessionBean構成,是一個典型的session facade模式。實際的系統大致是這樣:
在一個系統中同時使用CMP和Hibernate來做映射,是一個非常怪異的設計,這樣做只是為了使系統更有研究和討論的價值,實際應用中恐怕我自己也要仔細考慮是否採用BMP代替Hibernate。
編寫訊息bean之前,首先定義訊息中要傳遞的是什麼對象:
?
下面是訊息Bean的代碼:
/*
?* 訊息bean,處理針對Answer的操作
?* Created on 2004-7-27
?*/
package org.bromon.examer.message;
import javax.ejb.MessageDrivenBean;
import javax.jms.*;
import org.bromon.examer.base.*;
import org.bromon.examer.session.*;
public class AnswerMessageBean implements MessageDrivenBean, MessageListener
{
?private javax.ejb.MessageDrivenContext messageContext = null;
?//定義上下文
?public void setMessageDrivenContext(
??javax.ejb.MessageDrivenContext messageContext)
??throws javax.ejb.EJBException
?{
??this.messageContext = messageContext;
?}
?public void ejbRemove()
?{
??messageContext = null;
?}
?//收到訊息後將執行這個方法
?public void onMessage(javax.jms.Message message)
?{
??try
??{
???if(message instanceof ObjectMessage)
???{
????AnswerOperate ap=(AnswerOperate)((ObjectMessage)message).getObject();
????//調用EJB對AnswerOperate對象進行處理
???}
????System.out.printn("訊息處理完畢");
??}catch(Exception e)
??{
???System.out.println(e);
??}
?}
}
訊息如何保障安全呢?有兩個手段,一是使用訊息驗證,客戶必須提供匹配的帳號密碼才能訪問訊息中的資料。二是對訊息中的對象加密,客戶必須持有對應的密鑰才能獲得對象。