从零开始玩转JMX(三)——Model MBean
歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。
歡迎跳轉到本文的原文鏈接:https://honeypps.com/java/jmx-quick-start-3-model-mbean/
Model MBean
相對于Standard MBean,Model MBean更加靈活。如果我們不能修改已有的Java類,那么使用Model MBean是不錯的選擇。
Model MBean也是一種專門化的動態管理構件。它是預制的、通用的和動態的 MBean 類,已經包含了所有必要缺省行為的實現,并允許在運行時添加或覆蓋需要定制的那些實現。JMX規范規定該類必須實現為javax.management.modelmbean.RequiredModelMBean,管理者要做的就是實例化該類,并配置該構件的默認行為并注冊到JMX代理中,即可實現對資源的管理。JMX代理通過獲得一個ModelMBeanInfo對象來獲取管理接口。
模型管理構件具有以下新的特點:
- 持久性。定義了持久機制,可以利用Java的序列化或JDBC來存儲模型MBean的狀態。 就是要保存到硬盤上。
- 通知和日志功能。能記錄每一個發出的通知,并能自動發出屬性變化通知。
- 屬性值緩存。具有緩存屬性值的能力。
還是沿用前面的代碼,但是這里就不需要類似HelloMBean這樣的接口了。
package com.test.jmx.modelBean;public class Hello { //注意這里沒有implements任何東西private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void printHello(){System.out.println("Hello world, "+name);}public void printHello(String whoName){System.out.println("Hello, "+whoName);} }但是需要自己編寫一個產生Model MBean的工具類。Model MBean使用JDK提供的RequiredModelMBean,指定基本的Bean(Hello),創建好需要的ModelMBeanInfo就可以了。
package com.test.jmx.modelBean;import javax.management.*; import javax.management.modelmbean.*;/*** Created by hidden on 2016/10/9.*/ public class ModelMBeanUtils {private static final boolean READABLE = true;private static final boolean WRITABLE = true;private static final boolean BOOLEAN = true;private static final String STRING_CLASS = "java.lang.String";public static RequiredModelMBean createModelerMBean() {RequiredModelMBean model = null;try {model = new RequiredModelMBean();model.setManagedResource(new Hello(), "ObjectReference");ModelMBeanInfo info = createModelMBeanInfo();model.setModelMBeanInfo(info);} catch (Exception e) {e.printStackTrace();}return model;}private static ModelMBeanInfo createModelMBeanInfo() {//// 屬性 ////// 構造name屬性信息Descriptor portAttrDesc = new DescriptorSupport();portAttrDesc.setField("name", "Name");portAttrDesc.setField("descriptorType", "attribute");portAttrDesc.setField("displayName", "Name");portAttrDesc.setField("getMethod", "getName");portAttrDesc.setField("setMethod", "setName");ModelMBeanAttributeInfo nameAttrInfo = new ModelMBeanAttributeInfo(//"Name", // 屬性名STRING_CLASS, //屬性類型"people name", // 描述文字READABLE, WRITABLE, !BOOLEAN, // 讀寫portAttrDesc // 屬性描述);//// 方法 ////// 構造 getName操作描述符信息Descriptor getStateDesc = new DescriptorSupport(new String[] {"name=getName","descriptorType=operation","class=com.test.jmx.modelBean.Hello","role=operation"});ModelMBeanOperationInfo getName = new ModelMBeanOperationInfo(//"getName", //"get name attribute", //null, //"java.lang.String", //MBeanOperationInfo.ACTION, //getStateDesc //);// 構造 setName操作描述符信息Descriptor setStateDesc = new DescriptorSupport(new String[] {"name=setName", "descriptorType=operation", "class=com.test.jmx.modelBean.Hello","role=operation" });MBeanParameterInfo[] setStateParms = new MBeanParameterInfo[] { (new MBeanParameterInfo("name", "java.lang.String", "new name value")) };ModelMBeanOperationInfo setName = new ModelMBeanOperationInfo(//"setName", //"set name attribute", //setStateParms, //"void", //MBeanOperationInfo.ACTION, //setStateDesc //);//構造 printHello()操作的信息ModelMBeanOperationInfo print1Info = new ModelMBeanOperationInfo(//"printHello", //null, //null, //"void", //MBeanOperationInfo.INFO, //null //);// 構造printHello(String whoName)操作信息ModelMBeanOperationInfo print2Info;MBeanParameterInfo[] param2 = new MBeanParameterInfo[1];param2[0] = new MBeanParameterInfo("whoName", STRING_CLASS, "say hello to who");print2Info = new ModelMBeanOperationInfo(//"printHello", //null,//param2,//"void", //MBeanOperationInfo.INFO, //null//);//// 最后總合 ////// create ModelMBeanInfoModelMBeanInfo mbeanInfo = new ModelMBeanInfoSupport(//RequiredModelMBean.class.getName(), // MBean類null, // 描述文字new ModelMBeanAttributeInfo[] { // 所有的屬性信息(數組)nameAttrInfo },//只有一個屬性null, // 所有的構造函數信息new ModelMBeanOperationInfo[] { // 所有的操作信息(數組)getName,setName,print1Info,print2Info },//null, // 所有的通知信息(本例無)null//MBean描述);return mbeanInfo;} }這里著重說明下ModelMBeanInfo接口
編寫Model MBean的最大挑戰是告訴Model MBean對象托管資源的那些熟悉和方法可以暴露給代理。ModelMBeanInfo對象描述了將會暴露給代理的構造函數、屬性、操作甚至是監聽器。
創建了ModelMBeanInfo對象后,需要將其與ModelMBean對象關聯。目前有兩種方式可以做到這一點:
- 傳入ModelMBeanInfo對象給RequiredModelMBean對象的構造函數。
- 調用RequiredModelMBean對象的setModelMBeanInfo方法。
創建了ModelMBean對象后(RequiredModelMBean implements ModelMBean),需要調用ModelMBean接口的setManagedResource()方法將其與托管資源關聯,該方法如下:
public void setManagedResource(Object managedResource, String managedResourceType) ;managedResourceType的值可以為ObjectReference, Handle, IOR, EJBHandle或RMIReference,但當前只支持ObjectReference.
在注冊時沒有什么特別之處,只是需要注意下通過工具類獲得MBean即可
package com.test.jmx.modelBean;import com.sun.jdmk.comm.HtmlAdaptorServer;import javax.management.*; import javax.management.modelmbean.RequiredModelMBean; import java.lang.management.ManagementFactory;public class HelloAgent {public static void main(String[] args) throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException {MBeanServer server = ManagementFactory.getPlatformMBeanServer();ObjectName helloName = new ObjectName("MyMBean:name=HelloWorld");//Hello hello = new Hello();RequiredModelMBean hello = ModelMBeanUtils.createModelerMBean();server.registerMBean(hello, helloName);ObjectName adapterName = new ObjectName("MyMBean:name=htmladapter,port=8082");HtmlAdaptorServer adapter = new HtmlAdaptorServer();server.registerMBean(adapter, adapterName);adapter.start();} }運行結果:略。
Model MBean可以動態配置。試想一下這個應用場景:由于安全或其他原因,系統要把某個MBean公開的可管理方法隱藏起來。這時,如果你是用標準MBean,這需要修改接口類,然后重新編譯發布;如果用 Apache commons-modeler(如果不想總要維護MBean這個借口,那么可以使用Apache的commons-modeler來輔助開發MBean,所有的MBean都裝配在XML文件中)來寫的模型MBean,則只需要修改XML文件就行了,不需要重新編譯發布(可能要重啟一下系統)。這就是Model Mbean 優勢之所在了。
參考資料
歡迎跳轉到本文的原文鏈接:https://honeypps.com/java/jmx-quick-start-3-model-mbean/
歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。
總結
以上是生活随笔為你收集整理的从零开始玩转JMX(三)——Model MBean的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从零开始玩转JMX(二)——Condit
- 下一篇: 从零开始玩转JMX(四)——Apache