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();