天天看點

Essentials of the JMXstandard MBeanssending NotificationsIntroducing MXBeans

    MBean是被管理的Java對象,類似于JavaBean。它遵循Jmx規範中的設計模式。一個MBean能代表一個需要被管理的裝置,應用程式或其他資源。MBeans暴露了管理接口:一組可讀,可寫屬性和調用操作。管理接口在整個MBean執行個體生命周期總不會改變。當定義的事件發生時,MBean可以輸出通知。

    JMX規範定義了四種MBean類型:standard MBeans,dynamic MBean,open MBean和Model MBean。

standard MBeans

    standard MBean通過Java interface定義和一個實作此interface的類。接口中定義的每個方法要麼是屬性要麼是MBean的操作。預設每個方法定義了一個操作。屬性和操作是遵循特定設計模式的簡單方法。standard MBean由MBean interface和實作此接口的class(提供instrumented resource的功能)組成。

MBean interface

    下例是一個基本的MBean接口

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

    根據約定,MBean接口的名稱為類名+MBean。根據JMX規範,MBean接口由已命名的、可讀寫的屬性組成,且已命名的類型操作可以被應用程式(被MBean管理的)調用。上例中聲明了兩個操作add()和sayHello()。

    上例中的兩個屬性,Name是可讀的,cachesize是可讀、可寫的。get和set方法允許被管理的application通路和變更屬性值。就像JMX規範中,getter允許manager取讀屬性值。setter允許manager寫新的值到屬性中。

MBean Implementation

package com.example.mbeans;  
public class Hello implements HelloMBean { 
    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) { 
        this.cacheSize = size;  
        System.out.println("Cache size now " + this.cacheSize); 
    }  
    private final String name = "Reginald"; 
    private int cacheSize = DEFAULT_CACHE_SIZE; 
    private static final int DEFAULT_CACHE_SIZE = 200; 
}
           

     Java類Hello提供了接口HelloMBean中操作和屬性的定義。

Managing a Resource

    一旦resource被MBean裝配,resource的管理被JMX agent完成。JMX agent的一個核心是MBean server,它是一個被管理的對象server,MBeans在此server中注冊。JMX agent也包括一組服務來管理MBeans。

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

    如果沒有MBean server已經運作在平台上,getPlatformMBeanServer()方法會通過MBeanServerFactory.createMBeanServer()方法自動建立一個。每一個JMX MBean必須有一個object name,它是JMX類ObjectName的執行個體,且必須遵守JMX規範定義的文法:由domain和一組key-properties組成。在上例中,domain是"com.example.mbeans",key-property是對象的類型是Hello。

    HelloMBean在MBeanServer中注冊後,類Main會等待Hello上的管理操作。

Running the Standard MBean Example

    Java平台有management和moniter console,名為Jconsole,用來與MBean互動。運作上例的步驟:

1)編譯 javac com/example

2)啟動 java com.example.mbeans.Main

3)啟動Jconsole,從Jconsole中可以看到MBean。

sending Notifications

    MBean可以生成notification,例如可以發送狀态變更、被探測事件或一個問題的通知。對MBean來說,生成通知,必須實作NotificationBroadcaster或NotificationEmitter接口。剩下來需要做的事情就是構造javax.management.Notification執行個體或它的子類AttributeChangedNotification,傳遞給NotificationBroadcasterSupport。

    每個notification都有源,通知的源就是輸出notification的MBean的對象名稱。并且每個notification都有序列号,當順序至關重要且notification以錯誤順序處理時有很大危險,此号用來從同一個源來的Notification排序。

NotificationBroadcaster

package com.example.mbeans;  
import javax.management.*;  
public class Hello 
        extends NotificationBroadcasterSupport implements HelloMBean {  
    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);  
        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}; 
    }  
    private final String name = "Reginald"; 
    private int cacheSize = DEFAULT_CACHE_SIZE; 
    private static final int DEFAULT_CACHE_SIZE = 200;  
    private long sequenceNumber = 1; 
}
           

    MBeanNotification用來描述不同notification執行個體的特征。通過Jconsole,定于通知,當屬性變更時,就會收到通知。

Introducing MXBeans

    MXBean是一種新類型的MBean,它提供了簡單方式編碼MBean,僅僅引用之前定義的幾種類型。通過這種方式,我們可以确定你的MBean可以被任何用戶端使用,包括遠端用戶端。MXBean提供了一種便利的方式綁定相關值。與MBean類似,MXBean通過Java接口來定義,XXMXBean,java累實作此接口。然而不像标準MBean,MXBean不需要java類被稱為xx。在接口中定義的每個方法要麼是屬性要麼是操作。标注@MXBean可以用來标注Java接口,而不需要Java接口名稱遵循字尾MXBean。

    MXBeans背後的核心理念是類型諸如java.lang.manangement.MemoryUsage,它将在MXBean接口中被引用。java.lang.manangement.MemoryMXBean被映射成一組标準類型,被稱為open type(在javax.management.openmbean中定義)。映射規則可參見MXBean規範,但是簡單類型如int或string不會改變,然而複雜類型諸如MemoryUsage被 映射成标準類型CompositeDataSupport。

package com.example.mxbeans;  
public interface QueueSamplerMXBean { 
    public QueueSample getQueueSample(); 
    public void clearQueue(); 
}
package com.example.mxbeans;  
import java.util.Date; 
import java.util.Queue;  
public class QueueSampler implements QueueSamplerMXBean {      
    private Queue<String> queue;      
    public QueueSampler(Queue<String> queue) { 
       this.queue = queue; 
    }      
    public QueueSample getQueueSample() { 
        synchronized (queue) { 
            return new QueueSample(new Date(), queue.size(), queue.peek()); 
        } 
    }      
    public void clearQueue() { 
        synchronized (queue) { 
            queue.clear(); 
        } 
    } 
}  
package com.example.mxbeans;  
import java.beans.ConstructorProperties; 
import java.util.Date;  
public class QueueSample {      
    private final Date date; 
    private final int size; 
    private final String head; 
     
    @ConstructorProperties({"date", "size", "head"}) 
    public QueueSample(Date date, int size, String head) { 
        this.date = date; 
        this.size = size; 
        this.head = head; 
    }      
    public Date getDate() { 
        return date; 
    }      
    public int getSize() { 
        return size; 
    }      
    public String getHead() { 
        return head; 
    } 
} 
           
package com.example.mxbeans; 
 
import java.lang.management.ManagementFactory; 
import java.util.Queue; 
import java.util.concurrent.ArrayBlockingQueue; 
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.example.mxbeans:type=QueueSampler");          
        Queue<String> queue = new ArrayBlockingQueue<String>(10); 
        queue.add("Request-1"); 
        queue.add("Request-2"); 
        queue.add("Request-3"); 
        QueueSampler mxbean = new QueueSampler(queue);          
        mbs.registerMBean(mxbean, name);          
        System.out.println("Waiting..."); 
        Thread.sleep(Long.MAX_VALUE); 
    } 
} 
           

    運作Main類,啟動Jconsole,可以看到在接口中定義的方法getQueueSample傳回的對象被映射成CompositeType。

//jmxclient來擷取
MBeanServer mbs = ...whatever...; 
ObjectName name = new ObjectName("com.example.mxbeans:type=QueueSampler"); 
CompositeData queueSample = (CompositeData) mbs.getAttribute(name,  
                             "QueueSample"); 
int size = (Integer) queueSample.get("size"); 
//使用proxy方式
MBeanServer mbs = ...whatever...; 
ObjectName name = new ObjectName("com.example.mxbeans:type=QueueSampler"); 
QueueSamplerMXBean proxy = JMX.newMXBeanProxy(mbs, name,  
                                              QueueSamplerMXBean.class); 
QueueSample queueSample = proxy.getQueueSample(); 
int size = queueSample.getSize();
           
JMX