分类:
2008-10-16 19:26:02
图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所提供的优点的同时,也强调了其对于容量和安全方面的技术要求-这是使用这种新型技术所必须要求的。