表1 架構元素
(一) JMX通知模型
這個模型包含兩個部件:
·MBean-為本地和遠程注冊的聽者激活事件
·聽者-它用MBean注冊自己以聽取由該MBean所產生的事件
第一個由UserWeb Mbean來實現,第二個由ManagementListener來實現。
(二) 管理用戶信息的JMX MBean
UserWeb標准的MBean是一個簡單類-它包含關鍵的屬性和方法(表2)。
表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)。
因而,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所提供的優點的同時,也強調了其對於容量和安全方面的技術要求-這是使用這種新型技術所必須要求的。