天天看点

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