top
Loading...
基于JMX通知框架的AJAX深度開發
文章提示 AJAX和JMX分別位于系統管理棧的兩個對立端。然而,如今AJAX模型已普遍存在于豐富的瀏覽器客戶端。這使得該模型在構架領域為在問題解析管道中提高支持模式所具有的優點變得模糊起來。

本文將詳細描述一種AJAX架構的優點-它可以把管理狀態"廣播"到一個能夠使用瀏覽器的用戶基上而不必等待頁面更新。

這種架構是一個通用模型的擴展-可用于把JMX事件和屬性記載到一個服務器端日志文件中;而且,這種變化進一步把管理信息記錄或"廣播"到(支持AJAX的)用戶基。

在本文中,我們將特別分析AJAX請求/響應模型和把管理數據繪制到頁面的過程,還有漂亮的JMX通知框架-所有這些都通過一個裝配的servlet清晰地集成到一起。

接下來我們還會粗略地看一下通常在標準AJAX討論中所不及的內容-安全和容量模型。

本文中,我們使用BEA WebLogic 8.1用作這些軟件的發布平臺,盡管這里的架構和方法也適用于其它J2EE應用程序服務器。

一、關鍵需求

針對于企業Java和J2EE應用程序的系統管理棧形成了問題解析管道的一部分-在此,Java/J2EE應用程序與一個管理層進行交互以監視潛在的問題,例如應用程序服務器線程饑餓,堆溢出或到一個數據庫的陳舊連接等。

管理層通常包括JMX Mbeans-要裝配并使用哪個應用程序,以及其它一些產品例如讀取這些JMX屬性的Wily Introscope和HP OpenView-如果超過一個事先配置的門檻值,那么它能夠從Wily中得到警告。

這個模型存在一個問題-如果系統在后臺出現問題的話,針對JMX管理的服務器端模式將無法幫助瀏覽器端客戶,因為這種模型全部是以服務器為中心的。例如,如果一新的J2EE Web應用程序要被發布或該應用程序在幾分鐘內將要關閉-因為Wily檢測到一個問題,那么在瀏覽器上的用戶并不知道發生了這么緊迫的管理事件!

通過全面地允許用戶進入問題解析管道,系統管理員可以管理終端用戶體驗-通過把管理信息廣播到用戶基并在一定程度上控制用戶的行為來實現。

為了通過HTTP協議實現把管理信息傳遞給客戶,存在這樣一個問題:如果客戶端用戶不是公開地使用GET或POST更新頁面而是偷偷地更新一隱蔽的框架,那么管理方面如何把管理信息發送到一個HTTP客戶?

二、方案描述

本文要實現一簡單的AJAX腳本,它將從MBean服務器取得以XML消息形式的管理信息并經由一個servlet解決這個問題。這些管理信息必須被加以管理并且被反饋到所有的參與其中的能夠接收AJAX請求的應用程序服務器。

在服務器端:

·一個J2EE應用程序服務器簇用于服務于來自基于瀏覽器的用戶和在線事務處理(OLTP)用戶基(例如有兩個或四個服務器)的請求。通過使用一個第三方Web服務器,用戶請求被跨越該簇(OLTP簇)平衡裝載。

·一個標準MBean(UserWeb)用于存儲管理信息,如加上元數據屬性的管理消息。該Mbean宿主在J2EE"管理"服務器和在OLTP簇上的J2EE服務器上。

·在管理服務器上,由系統管理員使用針對JMX的HTMLAdaptor來設置警告狀態,重試間隔(在相鄰XMLHttp-Requests之間的間隔)以及警告消息-例如"System Down in 10 Minutes."。然后,管理員把該狀態廣播到管理服務器上的Mbeans-由該管理服務器來把它們的狀態重置到master管理狀態。

在客戶端:

·支持AJAX的客戶端使用一個XMLHttpRequest(它調用一個servlet以返回XML消息形式的相關的MBean值)來檢索狀態、重試間隔和消息。

·然后由客戶端JavaScript分析這個XML消息,重置重試間隔并且用管理消息重畫屏幕的一部分。

·在retry-interval秒之后,該客戶進行另外一個XMLHttpRequest并且客戶周期再次開始。

三、 基本架構

圖1顯示出全面的解決方案體系結構,其中表1描述了相應的基本架構元素。


圖1 方案架構

元素描述
標準MBean(UserWeb)用于警告狀態和消息的屬性,還有getter/setters和一個方法來廣播(通知)MBean狀態
MBean助理(UserWebMBeanHelper)包裝裝配的代碼以便于使用UserWeb MBean
MBean服務器J2EE容器內的MBean服務器
Servlet(Admin.java)裝配的Servlet,基于UserWebMBean的內容格式化XML響應
事件聽者
(ManagementListener.java)
Singleton-它用管理服務器上的UserWeb MBean把自己注冊為一個"alert.broadcast"類型事件的聽者
客戶端AJAX引擎(admin.js)用于管理XMLHttpRequest-/-repaint周期的JavaScript
客戶端描述(main.jsp)裝配的JSP。AJAX基于MBean屬性啟動該頁面
HTML適配器包裝器(StartHTMLAdaptor.java)在聽端口+100啟動一個HTMLAdaptorServer以實現到MBeans的HTTP存取
表1 架構元素

(一) JMX通知模型

這個模型包含兩個部件:

·MBean-為本地和遠程注冊的聽者激活事件

·聽者-它用MBean注冊自己以聽取由該MBean所產生的事件

第一個由UserWeb Mbean來實現,第二個由ManagementListener來實現。

(二) 管理用戶信息的JMX MBean

UserWeb標準的MBean是一個簡單類-它包含關鍵的屬性和方法(表2)。

元素描述
AlertEnabled如果AlertStatus>-1,則為真
AlertMessage用戶將在屏幕上看到的信息
AlertReady如果AlertStatus>0,則為真
CallBack在每兩個XMLHttpRequest之間的毫秒數
BroadcastState方法-它用一個事件(alert.broadcast)(它把Mbean狀態作為事件數據傳遞)來通知在本地/遠程JVM上的所有已注冊的聽者
表2 UserWeb Mbeam屬性和方法

(三) 事件聽者

Singleton ManagementListener類實現了Weblogic.management.RemoteNotificationListener-它擴展了javax.management.NotificationListener和java.rmi.Remote以允許在一個遠程WebLogic JVM上的事件通過使用RMI技術被通知到遠程聽者。
在應用程序服務器啟動時,在每個JVM上的一個聽者用管理服務器上的UserWeb MBean注冊自己。

(四) MBean助理

使用一個助理類來對Mbeans加以包裝是個不錯的注意。這樣,我們可以從裝配的代碼中調用這個助理從而調用MBean方法。
UserWebMBeanHelper類被用作UserWeb Mbean的包裝。所有助理的祖先是ApplicationMBeanHelper,它負責:

·查找本地和遠程MBean服務器

·調用這些服務器以取得/設置MBean屬性并且調用MBean方法

為了確保相匹配,MBean和MBean助理都實現接口UserWebMBean。

(五) 裝配Servlet

一個應用程序可以被裝配以使用JMX。用AOP術語來說就是,把管理方面織入到應用程序代碼中。本文中第一個JMX裝配點是一個HTTPServlet。這個servlet是AJAX請求的目標,并且它實現一個控制器模式-它可以被精心制作以使用簡單的請求參數來處理其它AJAX請求。
從一個MVC的角度來看,該模型是UserWeb Mbean,視圖是支持AJAX的(JSP)頁面,而控制器是被裝配的servlet。

(六) 客戶端AJAX引擎

這是一組JavaScript函數,它們:

·管理XMLHttpRequest并且響應處理重復性操作

·分析由XMLHttpRequest返回的XML消息

·用XML消息內容重畫屏幕

客戶描述

這是main.jsp頁面-它包含客戶端AJAX引擎和可重畫的部分。

(七) 序列

實質上,服務器端序列參與管理管理屬性的設置并且把這些屬性廣播到所有的感興趣(聽)的JVM上。而,客戶端序列參與檢索這些屬性并且以管理指定的間隔時間用重要的管理信息來重畫該HTML頁面。

(八) JMX通知(服務器序列)

·UserWeb MBeans和MBean事件聽者在應用程序服務器啟動時被使用相應的啟動類創建并且注冊

·管理員設置"master"UserWeb MBean屬性(警告消息和重試間隔),然后向宿主在遠程管理服務器上的聽者廣播或通知這一狀態

·遠程聽者處理通知-通過把master(通知)數據復制到本地UserWeb MBean實現

(九) XMLHttpRequest查詢(客戶序列)

·支持AJAX的客戶端間隔地調用一個servlet以查詢管理狀態

·該servlet讀取本地UserWeb MBean屬性,然后把它們插入到一個XML消息中并且返回該XML消息作為一個到瀏覽器客戶的XML響應(以后討論可供選擇的消息格式)

·然后,AJAX客戶分析XML文檔,提取警告和重試間隔等消息,重畫屏幕,然后使用這一重試間隔來設置下一個XMLHttpRequest的延遲時間。

下面詳細描述其中的每一步。

四、注冊MBeans和MBean聽者

在每一個J2EE服務器實例上,在服務器啟動時運行兩個啟動類:

·ManagementStartup-它把UserWeb MBean注冊到本地MBean服務器。Startup類參數包括警告狀態的默認設置,還有MBean名稱和MBean類。例如:

<StartupClass
Arguments="ServerName=admin,
MBeanName=ExampleApp:Name=UserWeb,
MBeanClass=com.grahamh.management.userWeb.UserWeb"
ClassName="com.grahamh.management.startup.ManagementStartup"
FailureIsFatal="true" Name="UserWEB" Notes=""
Targets="admin,OLTPCluster"/>

·MbeanRegistrations-它用管理服務器上的UserWeb MBean來注冊一個Singleton POJO-ManagementListener。

一個javax.management.NotificationFilterSupport對象被用于列舉UserWeb MBean將生成和聽者將接收的通知的類型:

//MbeanRegistrations.java
MBeanHelperFactory.getWebHelper().registerListener();
//UserWebMbeanListener.java
public void registerListener() throws UserWebException{
try {
//得到聽者和過濾
ManagementListener listener = MBeanHelperFactory.getListener();
NotificationFilterSupport filter = listener.getSupportedEvents();
//得到admin mbean服務器;
//用UserWeb MBean注冊該聽者和過濾
RemoteMBeanServer rmbs = getAdminMbeanServer();
rmbs.addNotificationListener("ExampleApp:Name=UserWeb", listener, filter, null);
}
catch (Exception e) {
throw new UserWebException("Unable to registerListener: "+ e.getMessage(), e);
}
}

該listener.getSupportedEvents()方法返回下面的過濾器(filter):

NotificationFilterSupport filter = new NotificationFilterSupport();
filter.enableType("alert.broadcast");

當ManagementListener在服務器啟動時,在(遠程的)管理服務器上建立一個到MBean服務器的連接,而且(本地的)ManagementListener被注冊為一個聽者-聽取在UserWeb MBean上生成的事件,并且有一個過濾器被設置為"alert.broadcast"事件類型。

因為該ManagementListener實現Weblogic.management.RemoteNotificationListener,所以它可以得到在本地JVM或一遠程JVM上生成的JMX通知;在本文中,是指在遠程管理服務器JVM上生成的JMX通知。

五、廣播Admin MBean屬性

管理和托管UserWeb Mbeans可以進行獨立地設置-這給任何一個J2EE服務器一個本地化的AJAX響應。然而,一個普通操作,管理和支持(OA&M)支持模式將設置admin MBean的屬性,然后使用通知模型把這些屬性廣播到遠程應用程序服務器上的MBeans,以備隨后的AJAX檢索之用。

因為該UserWeb MBean是基于ApplicationMBean-它擴展了javax.management.NotificationBroadcasterSupport,所以該基礎結構正適合于由UserWeb MBean來通知所有的聽者。因此,管理員設置相關的MBean屬性(使用HTMLAdaptor)并且點擊BroadcastState(見圖2)。


圖2 使用HTMLAdaptor看到的MBean視圖

因而,UserWeb.broadcastState()方法被執行-它同步地通知所有的聽者有關admin MBean的狀態:

public void broadcastState() throws Exception {
try {
Notification n = new Notification("alert.broadcast", "ExampleApp:Name=UserWeb", 0);
n.setUserData(new UserWeb(this));
this.sendNotification(n);
}
catch (Exception e) {
throw e;
}
}


因為數據在網絡上是串行化傳輸的,所以這種并非暫時的對象圖必須是可串行化的。

六、使用聽者接收來自MBean Props的通知

所謂的事件聽者就是ManagementListener Singleton。在管理服務器上的JMX通知框架遠程調用ManagementListener中的handleNotification()方法-該方法存在于每個OLTP簇JVMs(它們是在服務器啟動時注冊的)上的每一個聽者之中:

public void handleNotification(Notification notification, Object handback) {
System.out.println("Received alert: " + notification.getType());
//取得來自通知的事件userdata
Object userData = notification.getUserData();
if (userData instanceof UserWeb) {
//來自于destin8 Web
UserWeb WebVo = (UserWeb)userData;
UserWebMBeanHelper helper = MBeanHelperFactory.getWebHelper();
//使用MbeanHelper從值對象獲取數據并放入本地MBean中
helper.setAlertMessage(WebVo.getAlertMessage());
helper.setAlertStatus(WebVo.getAlertStatus());
helper.setCallBack(WebVo.getCallBack());
helper.setRefreshAlertStatus(WebVo.getRefreshAlertStatus());
}
}

"master" UserWeb數據被置入本地用戶Web MBean中-經由它的MBean助理來實現。因而,每個管理服務器被用master UserWeb狀態所更新。這就是JMX元素所具有的功能。

七、 管理狀態的AJAX請求

要使瀏覽器客戶端支持AJAX,需要具備如下:

·main.jsp-被裝配的JSP頁面,它能夠檢查(JMX)警告狀態并向服務器查詢警告。這個.jsp文件包括admin.js

·admin.js-這是一個JavaScript實用程序,它使用XMLHttpRequest來向服務器查詢管理狀態,分析XML響應,并且重畫屏幕的"status"區域

被包含在main.jsp中的JavaScript描述如下:

<script type="text/javascript" src="./js/admin.js" ></script>

不是連續地查詢,而是只有啟動瀏覽器警告功能時我們才進行查詢。我們使用UserWebMBeanHelper來檢查這個功能。如果該功能被啟動,那么當頁面加載時,JavaScript函數initAdmin()將被調用:

<%
if (MBeanHelperFactory.getWebHelper().isAlertEnabled()) {
%>
<body bgcolor="#F4FFE4" onload="initAdmin();">
<%
} else {
%>
<body bgcolor="#F4FFE4">
<%
}
%>

重畫的'status'屏幕區域定義如下:

<span id="adminBanner" class="style1"></span>

"adminBanner"將被使用來標記可重畫的區域-當分析XML響應并提取消息時。

這個initAdmin()方法調度一個JavaScript方法trapAlert()-這個方法在callbackTimeout毫秒后執行:

function setCallback() {
callBack = setTimeout('trapAlert()',callbackTimeout);
}
function initAdmin() {
setCallback();
}

注意,是由trapAlert()方法來實現啟動XMLHttpRequest:

function trapAlert() {
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.onreadystatechange = processRequest;
req.open("GET", './admin?reqid=0', true);
req.send(null);
}

在此,HTTP GET用來讀數據(只使用了一個小的請求參數),并且目標是admin servlet。這個請求是異步的,并且當請求狀態變化時,processRequest JavaScript函數被調用:

req.onreadystatechange = processRequest;

在繼續處理前等待一個響應,這看上去似乎非常合理;然而,如果一個網絡或服務器問題導致一個事務無法完成,那么你要冒著使你的腳本掛起來的危險。相比之下,一個相應于onreadystatechange事件的異步調用更為靈活些。

在請求完成時,processRequest事件處理器被調用:

function processRequest() {
if (req.readyState == 4) {
if (req.status == 200) {
parseMessages();
}
....
setCallback();//只有完成時才這樣做
}
}

列表1(見下載源碼)顯示了所有可用的狀態碼。當請求完成并且返回HTTP狀態代碼200(OK)時,parseMessages()方法被調用以從XML消息中提取數據。然后,再次調度trapAlert()方法。如果XML響應有一個不同的重試間隔,那么這個值會由parseMessages()函數設置。

八、分析XML響應并重畫屏幕

parseMessages()函數首先提取XML響應

response = req.responseXML;

然后,它提取有關警告狀態,警告文本和重試間隔等的元素:

itemStatus = response.getElementsByTagName('status')[0].firstChild.nodeValue;
itemText = response.getElementsByTagName('textBody')[0].firstChild.nodeValue;
callbackTimeout = parseInt(response.getElementsByTagName('callBack')[0].firstChild.nodeValue);

然后,警告文本被重畫到adminBanner文檔元素(見上):

document.getElementById("adminBanner").innerHTML= itemText;

該警告消息顯示在如圖3所示的屏幕上。


圖3 重畫的屏幕

九、Servlet格式化XML響應

為了使瀏覽器把管理警告顯示給用戶,需要使用XMLHttpRequest來請求管理狀態。

當瀏覽器發送請求時,該servlet使用MBean助理來檢查警告狀態并且,如果一警告可用,即構建一個XML文檔作為響應。

如果沒有返回狀態,那么響應狀態被設置如下:

response.setStatus(HttpServletResponse.SC_NO_CONTENT);

否則,該文本/XML響應類型被設置為:

response.setContentType("text/xml");

列表2顯示了完整的servlet方法。

當該servlet被調用并且返回XML內容時,控制臺應該打印出:

Received alert: alert.broadcast
<message>
<status>1</status>
<textBody>
<![CDATA[System Down in 10 Minutes]]>
</textBody>
<callBack>10000</callBack>
</message>


十、容量建模和安全性

因為AJAX以有趣的方式開通了架構,所以存在兩個關鍵方面要求加以考慮:

·容量建模

·安全性

當然,緩沖和響應消息類型(XML或文本)也都是比較重要的。

十一、容量建模

支持AJAX的豐富的客戶端不必再如以前那樣頻繁地提交請求。但是隨著XMLHttpRequest異步地執行在瀏覽器端,向服務器發出的HTTP請求的數目也會相應于重試間隔而有所增加。

·再試間隔(思考時間)=20秒

·連接的用戶數=5000

·事務每秒(TPS)=5000/20=250

我們期望一個由HTTP用戶基所產生的額外的每秒能夠實現250次的請求(事務)。

當然,這依賴于在服務器上的這些請求所完成的任務來提高響應時間上的潛力。在我們的實例中,每個請求必須查找MBean屬性并且格式化一個XML響應,但是該響應很小而且MBean處理是在本地內存中。由于每個Web服務器線程每秒能夠處理大約200個GET請求,以及用戶橫跨一個大約運行著200個線程的J2EE服務器來請求平衡加載,所以增加的加載并不太重要。

還應注意,當建模AJAX架構時,增加的加載數可能隨著帶寬的減少而有所偏移。

十二、安全性

假定你只要求WebUser組中的用戶能夠存取該admin servlet,情況會怎樣呢?

如果僅是被認證的用戶才能存取admin servlet,那么XMLHttpRequest將以該用戶身份運行-如果該用戶已經認證。

例如,一旦用戶Joe登錄進這個應用程序,并且Joe是一個WebUser組的成員,那么XMLHttpRequest將能激活admin servlet。

把下列代碼添加到admin servlet將會確認被認證的主題,并分別返回true和Joe:

request.isUserInRole("WebUser");
request.getRemoteUser();

十三、緩沖

一些用戶已經發現IE會緩沖來自AJAX請求的響應;這可能是由于瀏覽器/頁面設置,但是一個強制性的解決辦法是為該URL加上時間印戳:

var urlstr = "./admin?reqId=0&ts=" + new Date().getTimeStamp();

十四、用不用XML?

一些AJAX設計者欣然棄用XML而發送以普通文本形式的響應:

response.setContentType("text/plain");

這明顯要依賴于你的客戶端需求和客戶與所需求的數據之間的耦合程度。一個簡單的文本響應對于一個文本警告就足夠了;然而,本文中XML模型的優點在于,響應數據可以被進一步詳細描述從而提煉狀態和狀態相關的數據。本文向你展示了怎樣分析一更復雜的響應-客戶可能必須編碼以進行接收之。

十五、 結論

AJAX代表了一些新型的架構機會,然而它們不應該被豐富的客戶端功能所遮蔽。本文在衡量了AJAX所提供的優點的同時,也強調了其對于容量和安全方面的技術要求-這是使用這種新型技術所必須要求的。
作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗