JMX(Java Management Extension)學習


基本概念

JMX(Java Management Extensions)是一個為應用程序植入管理功能的框架。

JMX讓程序有被管理的功能,例如你開發一個WEB網站,它是在24小時不間斷運行,那么你肯定會對網站進行監控,如每天的UV、PV是多少;又或者在業務高峰的期間,你想對接口進行限流,就必須去修改接口並發的配置值。

JMX框架主要由以下幾層構成:

  • 探針層(Probe Level)/設備層(Instrumentation Level)
  • 代理層(Agent Level)
  • 遠程管理層(Remote Management Level)

它們之間的關系如下圖所示:

pic

需要通過JMX服務獲得被管理對象信息的程序,就是通過遠程管理層來與具體的MBean進行交互的。

分別介紹一下比較重要的一些概念:

  • MBean(Managed Bean)

通常是一個 Java 類,它提供接口可以使這個類具有可以被管理(能夠成功注冊到server上)的功能。它通常代表我們想要實際管理的一個程序,或者一個設備等等,這是我們用MBean的規范將管理對象封裝了起來。

  • MBeanServer

是管理MBean的一個 Java 類,你需要向 MBeanServer 注冊一個 MBean 后,這個 MBean 才會真正具備被管理的能力,MBeanServer 還提供了查詢功能和注冊監聽器的功能,sun 提供的只是接口,不同的 JMX 實現中的 MBean server 實現也不同。

  • JMX Agent

Agent 是 MBean Server 的容器,主要為了管理一系列的 MBean,並且提供的一系列的服務,通常有MBean relationships, dynamically loading classes, simple monitoring services, timers。Agent 可以利用 Protocol adapters(例如 HTTP 和 SNMP)和 connectors(RMI 和Jini)使不同的客戶端可以訪問 MBean。

  • Protocol adapters 和 connectors

適配器和連接器主要使不同的協議和客戶端可以使用這個 Agent,一個 Agent 中可以有多個 Protocol adapters 和 connectors,這樣管理起 MBean 來就更方便了(有多種類型的客戶端和協議可以操作 MBean)。注意,Protocol adapters 和 connectors 通常也是 MBean。

【JMX學習】1、jmx入門

JMX超詳細解讀

MBean的種類

  • standard MBean:需要定義MBean接口,接口中包含需要被管理的資源,並編寫MBean接口的實現類。接口和實現類的命名必須滿足一定規范,若實現類名為Classname,則接口的命名必須為ClassNameMBean。
  • dynamic MBean:必須實現javax.management.DynamicMBean接口,所有的屬性,方法都在運行時定義。
  • open MBean:此MBean的規范還不完善,正在改進中
  • model MBean:與標准和動態MBean相比,你可以不用寫MBean類,只需使用javax.management.modelmbean.RequiredModelMBean即可。RequiredModelMBean實現了ModelMBean接口,而ModelMBean擴展了DynamicMBean接口,因此與DynamicMBean相似,Model MBean的管理資源也是在運行時定義的。與DynamicMBean不同的是,DynamicMBean管理的資源一般定義在DynamicMBean中(運行時才決定管理那些資源),而model MBean管理的資源並不在MBean中,而是在外部(通常是一個類),只有在運行時,才通過set方法將其加入到model MBean中。

JMX學習筆記(一)-MBean

StandardMBean

從零開始玩轉JMX(一)——簡介和Standard MBean

JMX學習筆記(三):MXBean

MXBean相比MBean支持更復雜數據類型的類屬性管理

DynamicBean

動態MBean:DynamicMBean

ModelMBean

從零開始玩轉JMX(三)——Model MBean

JMX的實現方式

StandardMBean的使用方法

  1. 定義MBean接口
  2. 編寫MBean接口實現類
  3. 創建MBeanServer類,並向server注冊MBean類(server.registerMBean(實現類對象,ObjectName)) 【ObjectName取名是有規范的,格式為:“域名:name=MBean名稱”,其中域名和MBean的名稱可以任意取。這樣定義后,就可以唯一標識我們定義的這個MBean的實現類了。】
  4. 為了查看實現狀態,可以再加一個Thread.sleep(Long.MAX_VALUE),然后用JConsole工具查看。

JMX服務的訪問方式

JMX服務可以有多種方式對其進行連接和使用,也有不同的展現方式,但內容都是相同的。

1.JDK自帶工具JConsole(jdk/bin/jconsole.exe)

  • 首先連接JMX服務。

    JMX服務或者是本地提供,或者是遠程提供,本地提供可以直接在jconsole的連接界面上顯示,選中連接即可。遠程提供的連接,則需要輸入遠程地址和端口號,並且如果設置了帳號密碼還需要輸入帳號密碼,然后連接。

pic

  • 連接成功后,可以看到如文件目錄形式展現的MBean,可以點擊展開,查看屬性,或者實時調用方法(在MBean接口實現類中實現的非屬性相關的get/set方法都可以調用)。

2.通過JMX提供的工具頁訪問

這里需要到導入外部jar包jdmk

package jmx;

import java.lang.management.ManagementFactory;

import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.ObjectName;

import com.sun.jdmk.comm.HtmlAdaptorServer;

public class HelloAgent
{
    public static void main(String[] args) throws JMException, Exception
    {
         MBeanServer server = ManagementFactory.getPlatformMBeanServer();
         ObjectName helloName = new ObjectName("jmxBean:name=hello");
         //create mbean and register mbean
         server.registerMBean(new Hello(), helloName);
         
         //這里需要對Html適配器的MBean進行注冊,並啟動適配器,這樣就可以通過網頁來使用JMX。
         ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8082");   
         HtmlAdaptorServer adapter = new HtmlAdaptorServer();   
         server.registerMBean(adapter, adapterName);  
         adapter.start();
    }
}

訪問地址:http://localhost:8082,點擊name=hello:

pic

3.通過客戶端程序進行遠程訪問(RMI)

當然,需要先啟動JMX服務,並監聽端口才可以訪問。

package jmx;

import java.io.IOException;

import javax.management.Attribute;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;


public class Client
{
    public static void main(String[] args) throws IOException, Exception, NullPointerException
    {
        /**
         * JMX提供服務的url
         * @type {JMXServiceURL}
         */
        JMXServiceURL url = new JMXServiceURL
            ("service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi");
        
        /**
         * JMX服務連接器,用於發起連接
         * @type {[type]}
         */
        JMXConnector jmxc = JMXConnectorFactory.connect(url,null);
        
        /**
         * 從JMX服務連接器上獲取的MBeanServer連接器。
         * @type {[type]}
         */
        MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
        //ObjectName的名稱與前面注冊時候的保持一致
        ObjectName mbeanName = new ObjectName("jmxBean:name=hello");
        
        System.out.println("Domains ......");
        
        //獲得所有server下的域名
        String[] domains = mbsc.getDomains();
        
        for(int i=0;i<domains.length;i++)
        {
            System.out.println("domain[" + i + "]=" + domains[i] );
        }
        
        //獲得所有注冊在該server上的MBean數目
        System.out.println("MBean count = " + mbsc.getMBeanCount());

        //設置指定Mbean的特定屬性值
        //這里的setAttribute、getAttribute操作只能針對bean的屬性
        //例如對getName或者setName進行操作,只能使用Name,需要去除方法的前綴
        mbsc.setAttribute(mbeanName, new Attribute("Name","杭州"));
        mbsc.setAttribute(mbeanName, new Attribute("Age","1990"));
        String age = (String)mbsc.getAttribute(mbeanName, "Age");
        String name = (String)mbsc.getAttribute(mbeanName, "Name");
        System.out.println("age=" + age + ";name=" + name);
        
        
        /**
         * 通過JMX調用MBean實例的方法
         */
        
        //方法一
        //通過獲得代理調用MBean實例的方法
        HelloMBean proxy = MBeanServerInvocationHandler.
            newProxyInstance(mbsc, mbeanName, HelloMBean.class, false);
        proxy.helloWorld();
        proxy.helloWorld("migu");
        proxy.getTelephone();
        
        //方法二
        //通過msbc的invoke方法調用MBean實例的方法,只針對非屬性的相關的方法(get/set)
        //例如invoke不能對getName方法進行調用
        mbsc.invoke(mbeanName, "getTelephone", null, null);
        mbsc.invoke(mbeanName, "helloWorld", 
            new String[]{"I'll connect to JMX Server via client2"}, new String[]{"java.lang.String"});
        mbsc.invoke(mbeanName, "helloWorld", null, null);
    }
}

JMX——Notifications

從零開始玩轉JMX(二)——Condition

JMX學習筆記(四):Notifications

JMX API定義了一種機制,使MBean能生成通知,如當信號狀態改變,檢測到事件或者一個問題時。

通知模型僅僅涉及了在同一個JMX代理中的管理構件之間的事件傳播。JMX通知模型依靠以下幾個部分:

  • Notification,一個通用的事件類型,該類標識事件的類型,可以被直接使用,也可以根據傳遞的事件的需要而被擴展。
  • NotificationListener接口,接受通知的對象需實現此接口。
  • NotificationFilter接口,作為通知過濾器的對象需實現此接口,為通知監聽者提供了一個過濾通知的過濾器。
  • NotificationBroadcaster接口,通知發送者需實現此接口,該接口允許希望得到通知的監聽者注冊。

發送一個通用類型的通知,任何一個監聽者都會得到該通知。因此,監聽者需提供過濾器來選擇所需要接受的通知。任何類型的MBean,標准的或動態的,都可以作為一個通知發送者,也可以作為一個通知監聽者,或兩者都是。

要生成通知,MBean必須實現NotificationEmitter接口或繼承NotificationBroadcasterSupport類。要發送一個通知必須構造Notification類的實例或者子類(如NotificationChangedAttribute),通知實例產生后,由NotificationBroadcasterSupport的sendNotification方法發送通知。

  • 例子:

Step 1 :定義HelloMBean接口

    package com.jmx.demo5;  
      
    public interface HelloMBean {  
        public void sayHello();  
      
        public int add(int x, int y);  
      
        public String getName();  
      
        public int getCacheSize();  
      
        public void setCacheSize(int size);  
      
    }  

Step 2 :編寫HelloMBean的實現類Hello

    package com.jmx.demo5;  
      
    import javax.management.AttributeChangeNotification;  
    import javax.management.MBeanNotificationInfo;  
    import javax.management.Notification;  
    import javax.management.NotificationBroadcasterSupport;  
      
    //MBean must extends NotificationBroadcasterSupport or implements NotificationEmitter  
    public class Hello extends NotificationBroadcasterSupport implements HelloMBean {  
        private final String name = "Reginald";  
        private int cacheSize = DEFAULT_CACHE_SIZE;  
        private static final int DEFAULT_CACHE_SIZE = 200;  
        private long sequenceNumber = 1;  
      
        public void sayHello() {  
            System.out.println("hello, world");  
        }  
      
        public int add(int x, int y) {  
            return x + y;  
        }  
      
        public String getName() {  
            return this.name;  
        }  
      
        public int getCacheSize() {  
            return this.cacheSize;  
        }  
      
        public synchronized void setCacheSize(int size) {  
            int oldSize = this.cacheSize;  
            this.cacheSize = size;  
            System.out.println("Cache size now " + this.cacheSize);  
      
            /** 
             * To send a notification,you need to construct an instance of class 
             * Notification or a Subclass(such as AttributeChangedNotification),and 
             * pass the instance to NotificationBroadcastSupport.sendNotification. 
             *  
             */  
            Notification n = new AttributeChangeNotification(this,  
                    sequenceNumber++, System.currentTimeMillis(),  
                    "CacheSize changed", "CacheSize", "int", oldSize,  
                    this.cacheSize);  
      
            sendNotification(n);  
        }  
      
        @Override  
        public MBeanNotificationInfo[] getNotificationInfo() {  
            String[] types = new String[] { AttributeChangeNotification.ATTRIBUTE_CHANGE };  
            String name = AttributeChangeNotification.class.getName();  
            String description = "An attribute of this MBean has changed";  
            MBeanNotificationInfo info = new MBeanNotificationInfo(types, name,  
                    description);  
            return new MBeanNotificationInfo[] { info };  
        }  
      
    }  

Step 3:創建MBeanServer,標識MBean,注冊MBean,並運行Main方法:

    package com.jmx.demo5;  
      
    import java.lang.management.ManagementFactory;  
      
    import javax.management.MBeanServer;  
    import javax.management.ObjectName;  
      
    public class Main {  
        public static void main(String[] args) throws Exception{  
            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();  
            ObjectName name = new ObjectName("com.jmx.demo:type=Hello");  
            Hello mbean = new Hello();  
            mbs.registerMBean(mbean, name);  
            System.out.println("Waiting forever...");  
            Thread.sleep(Long.MAX_VALUE);  
              
        }  
    }  

然后可以用jconsole打開JMX服務,查看運行結果:通知選項初始狀態沒有值,點擊訂閱后,通知項為0

pic

更改CacheSize的值后,在觀察通知選項,變為1

pic

總結:

Notification可以用於監測任何有關MBean方法調用的信息,只要MBean實現類繼承NotificationBroadcasterSupport類,然后在需要監測的方法中調用NotificationBroadcasterSupport處繼承來的sendNotification(Notification n)方法即可,而方法的參數是一個Notification實例,需要傳入相關的通知信息。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM