JMX的用處及用法

JMX最常見的場景是監控Java程序的基本信息和運行情況,任何Java程序都可以開啓JMX,然後使用JConsole或Visual VM進行預覽。下圖是使用Jconsle通過JMX查看Java程序的運行信息

爲Java程序開啓JMX很簡單,只要在運行Java程序的命令後面指定如下命令即可

-Djava.rmi.server.hostname=127.0.0.1
-Dcom.sun.management.jmxremote.port=1000
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

我們從Jconsole的視圖標籤中見到,JConsole通過JMX展示的信息都是Java程序的通用信息,如內存情況、線程情況、類加載情況等,換言之,只要是Java程序就都具備這些信息。這些信息爲我們優化程序性能、排查BUG非常有用,而JMX就是獲取這些信息的基礎,因此它是一種非常有用的技術。

然而JMX的強大遠不止此,它出了能提供一些通用的信息以外,還能通過特定的編程接口提供一些針對具體程序的專有信息並在JConsole等JMX客戶端工具中展示,具體點說就是程序員可以把需要展示的信息放在一種叫做MBean的Java對象內,然後JConsole之類的客戶端工具可以連接到JMX服務,識別MBean並在圖形界面中顯示。從純抽象的角度觸發,這其實有點像瀏覽器發送一個請求給http服務器,然後http服務器執行瀏覽器的請求並返回相應的數據,從某種角度來說JConsole和JMX也是以這種方式工作的,只是它們使用的協議不是http,交換數據協議格式不是http數據包,但是他們的確是以客戶端/服務器這種模式工作的,而且完成的事情也差不多。

那麼既然有了http,JMX又有何存在意義呢。 事實上,JMX能完成的任務通過http的確都能完成,只不過某些情況下用JMX來做會更加方便。

比如說你需要知道服務器上個運行中程序的相關信息, 如執行了多少次數據庫操作、任務隊列中有多少個任務在等待處理

最常用的解決方案,我們會在程序中啓動一個http服務,當接收到來自客戶端的請求這些信息的請求時,我們的http處理程序會獲得這些信息,並轉換成特定格式的數據如JSON返回給客戶端,客戶端會以某種方式展現這些信息。

如以JMX作爲解決方案,核心流程也是如此,但在數據的交換方式上會略有不同。

下面我們展示JMX是如何完成此任務的。

一、定義一個展示所需信息的MBean接口

public interface ServerInfoMBean {
    int getExecutedSqlCmdCount();
}

在使用 Standard Mbean 作爲數據傳輸對象的情況下這個接口的定義是必須的, 並且接口名稱必須以“MBean”這個單詞結尾。

二、實現具體的MBean

public class ServerInfo implements ServerInfoMBean {
    public int getExecutedSqlCmdCount() {
        return Dbutil.getExecutedSqlCmdCount();
    }
}

三、在程序的某個地方啓動JMX服務並註冊ServerInfoMBean

    public static void main(String[] args)  throws JMException, Exception{
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        ObjectName name = new ObjectName("serverInfoMBean:name=serverInfo");
        server.registerMBean(new ServerInfo(), name);
    }

四、運行程序,並通過JConsole查看

如果程序運行在本地,Jconsole會自動檢測到程序的進程,鼠標雙擊進入即可

在JConsole下面即會展示我們定義的MBean中的內容

那麼假如Java程序並非運行在本地而是運行在遠端服務器上我們應該如何通過客戶端去連接呢, 很簡單,只要使用JDK提供的JMX類庫監聽端口提供服務即可

                  
public class Main {
    public static void main(String[] args)  throws JMException, Exception{
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        ObjectName name = new ObjectName("serverInfoMBean:name=serverInfo");
        server.registerMBean(new ServerInfo(), name);


        LocateRegistry.createRegistry(8081);
        JMXServiceURL url = new JMXServiceURL
                ("service:jmx:rmi:///jndi/rmi://localhost:8081/jmxrmi");
        JMXConnectorServer jcs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, server);
        jcs.start();
    }
}

或者在啓動Java程序指定命令行參數也

-Djava.rmi.server.hostname=127.0.0.1
-Dcom.sun.management.jmxremote.port=10086
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

<br />然後使用JConsole的連接遠端進程功能即可

其餘的操作和本地無差。

這相對於提供一個http服務來完成任務是不是要簡單了不少,http是一個更加抽象、應用面更廣泛、功能更強大的服務,因此所作的工作也要更多一些。JMX則是一個更加具體、應用面不那麼廣、功能也沒有http強大的服務,不過呢它勝在解決特定問題更加輕鬆方便,上面的示例已經很好的說明了。

此外,JMX和Jconsole並不僅僅只能展示數據,它還能執行Java方法。以上面的示例爲基礎我們再進行一系列改進。

一、擴展ServerInfoMBean接口和實現的類

public interface ServerInfoMBean {
    int getExecutedSqlCmdCount();
    void printString(String fromJConsole);
}

public class ServerInfo implements ServerInfoMBean {
    public int getExecutedSqlCmdCount() {
        return 100;
    }

    public void printString(String fromJConsole) {
        System.out.println(fromJConsole);
    }
}

二、運行程序並使用JConsole連接

mbean頁籤中出現了我們新添加的方法

三、點擊printString按鈕調用方法

方法被調用,同時控制檯也打印了通過Jconsole傳遞的參數

這裏只是講解了JMX的用處和最基礎的使用方法,顯然JMX真正提供的功能遠不及此,比如它可以不用JConsole而是客戶端編程的方式訪問等等, 有興趣的同學可以深入研究。

總而言之, 我覺得JMX是一種小巧精悍的工具,在不需要大張旗鼓的通過http或者其他server\client方式提供服務時,就是他發揮用處的時機了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章