一、 引言
首先我們要分析一個簡單的web應用程序,它監控已經登陸的用戶數目并通過一個安全的JMX服務來顯示該項統計。我們還將運行這個應用程序的多個實例并且從所有的運行實例中跟蹤這個統計數字。當然,你可以下載這個示例web應用程序。它需要你安裝J2SE 5.0 SDK并且你的JAVA_HOME環境變量指向基安裝目錄。J2SE 5.0實現了1.2版本的JMX API和JMX 1.0版本的Remote API。同時還需要一個支持servlet的容器;我使用的是Apache Tomcat 5.5.12。另外,我還使用Apache Ant來構建這一示例應用程序。
二、 建立示例應用程序
首先,你要下載示例應用程序并且使用 ant war(更多的細節見build.xml中的注釋)來創建一個WAR文件。把jmxapp.war復制到Tomcat的webapps目錄。假定 Tomcat正在運行于你的本地機器的端口8080,那么該應用程序的URL將是:
http://localhost:8080/jmxapp
如果你看到一個提示你輸入名字和口令的登陸屏幕,那么一切已經就緒了。
三、 跟蹤一些有意義的數據
本文中的應用程序使用Struts框架來提交登錄表單。一旦提交結束,即執行LoginAction.execute(..)方法-它將簡單地檢查是否用戶的ID為"hello"以及是否其口令為"world"。如果二者都正確,那么登錄成功并且控制被導向login_suclearcase/" target="_blank" >ccess.jsp;如果不正確,那么我們返回到登錄表單。根據登錄成功與否決定調用incrementSuccessLogins(HttpServletRequest)方法還是 incrementFailedLogins(HttpServletRequest)方法?,F在,讓我們先分析一下 incrementFailedLogins(HttpServletRequest):
private void incrementFailedLogins(HttpServletRequest request) { HttpSession session = request.getSession(); ServletContext context =session.getServletContext(); Integer num = (Integer) context.getAttribute( Constants.FAILED_LOGINS_KEY); int newValue = 1; if (num != null) { newValue = num.intValue() + 1; } context.setAttribute( Constants.FAILED_LOGINS_KEY, new Integer(newValue)); } |
public interface LoginStatsMBean { public int getFailedLogins(); public int getSuccessLogins(); } |
public int getFailedLogins() { ServletContext context = Config.getServletContext(); Integer val = (Integer) context.getAttribute( Constants.FAILED_LOGINS_KEY); return (val == null) ? 0 : val.intValue(); } |
public class JMXAgent { public JMXAgent() { //初始化JMX服務器 } public void start() { //啟動JMX服務器 } //在應用程序結束時調用 public void stop() { //停止JMX服務器 } } |
MBeanServer server = MBeanServerFactory.createMBeanServer(DOMAIN); server.registerMBean(new LoginStats(),new ObjectName(DOMAIN+ ":name=LoginStats")); |
JMXServiceURL url = new JMXServiceURL("rmi",null, Constants.MBEAN_SERVER_PORT, "/jndi/rmi://localhost:" +Constants.RMI_REGISTRY_PORT +"/jmxapp"); |
ServletContext context = Config.getServletContext(); //得到存儲jmx用戶信息的文件 String userFile =context.getRealPath("/")+"/WEB-INF/classes/"+Constants.JMX_USERS_FILE; //創建authenticator并且初始化RMI服務器 Map<string> env = new HashMap<string>(); env.put("jmx.remote.x.password.file", userFile); 現在,讓我們創建JMXConnectorServer。下面一行代碼完成這一功能: connectorServer = JMXConnectorServerFactory. newJMXConnectorServer(url, env, server); |
這個JMXConnectorServerFactory.newJMXConnectorServer(JMXServiceURL,Map, MBeanServer)方法使用我們剛創建的三個對象作為參數-它們是JMXServiceURL,存儲認證信息的映射和MBeanServer。其中,connectorServer實例變量允許我們分別在應用程序啟動和停止時,分別用start()和stop()來啟動和停止 JMXConnectorServer。
提示 盡管JSR 160的J2SE 5.0實現相當有力;但是另外的實現,例如MX4J,也提供了一些類-它們提供了方便的特性,例如口令混淆,也就是PasswordAuthenticator類。
七、 啟動RMI注冊
在早些時候,我提到RMI注冊并且指出當訪問服務時執行一個JNDI查詢。然而,現在我們沒有一個正運行的RMI注冊,因此一個JNDI查詢將失敗。一個RMI注冊的啟動可以用手工方式或編程方式來實現。
(一) 使用命令行
在你的Windows或Linux命令行上,輸入下列一名來啟動一個RMI注冊:
rmiregistry &
這將啟動你的默認主機和端口(分別是localhost和1109)的RMI注冊。然而,對于我們的web應用程序來說,我們不可能依賴一個在應用程序啟動時可用的RMI而寧愿用編程方式來實現之。
(二) 以編程方式啟動RMI注冊
為了以編程方式啟動RMI注冊,你可以使用LocateRegistry.createRegistry(int port)方法。該方法返回類型注冊的一個對象。當我們想在應用程序一端終止這個注冊時,我們保存這個參考。就在我們啟動我們的在 JMXAgent.start()中的JMXConnectorServer之前,我們首先啟動RMI注冊,使用下列代碼行:
registry = LocateRegistry.createRegistry(Constants.RMI_REGISTRY_PORT);
在應用程序一端,在JMXAgent.stop()中停止JMXConnectorServer之后,調用下列方法來終止該注冊:
UnicastRemoteObject.unexportObject(registry,true);
注意,StartupListener類觸發了應用程序開始和結束任務。
八、 訪問我們的JMX服務
我們可以有好幾種方法來存取JSR 160服務。為此,我們可以通過編程或通過使用一個GUI來實現。
(一) 使用MC4J連接
通過把jmxapp.war復制到Tomcat的webapps目錄來發布該應用程序。下載并且安裝MC4J。一旦安裝完,創建一新的類型JSR 160的服務器連接并且指定該服務器URL-它在應用程序啟動時在應用程序服務器日志中打印。在我的示例中,它是:
service:jmx:rmi://zarar:9589/jndi/rmi://localhost:1100/jmxapp
提供用戶名和口令,MC4J分別把它們參考為"Principle"和"Credentials"。點擊Next將把你帶到一個屏幕-在此你可以定制你的classpath。默認設置應該工作正常,并且你可以點擊"Finish"來連接到該JMX服務。一旦建立連接,瀏覽如圖1所示的MC4J樹結構,直到你找到LoginStats MBean實現的"Properties"選項。
![]() 圖1.MC4J視圖 |
![]() 圖2.屬性窗口 |
![]() 圖3."添加應用程序"頁面 |
![]() 圖4.添加應用程序簇頁面 |
![]() 圖5.針對jmxapp和jmxapp2的簇視圖 |
(責任編輯:城塵)