JMX解读

JMX

主要分为五类:

  • Standard MBeans
  • Dynamic MBeans
  • Open MBeans
  • Model MBeans
  • MXBeans

Standard MBeans

Standard MBean 一般用于管理相对比较稳定的资源。一般对于Standard MBean,我们会使用显式声明的管理接口(我们自己定义的),这些接口一旦创建之后就不再改变。

package com.example; 
 
public interface HelloMBean { 
 
    public void sayHello(); 
    public int add(int x, int y); 
    
    public String getName(); 
     
    public int getCacheSize(); 
    public void setCacheSize(int size); 
} 
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; 
}
package com.example; 
 
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:type=Hello"); 
        Hello mbean = new Hello(); 
        mbs.registerMBean(mbean, name); 
        System.out.println("Waiting forever..."); 
        Thread.sleep(Long.MAX_VALUE); 
    } 
}

可以通过页面或者jconsole等工具改变属性值

Dynamic MBeans

​ DynamicMBean是在运行期才定义它的属性和方法,也就是说它有什么属性和方法是可以动态改变的。动态MBean主要利用一些辅助类(构造函数类MBeanConstructorInfo、属性类MBeanAttributeInfo、方法类MBeanOperationInfo)来完成这个功能,所有的DynamicMBean必须实现DynamicMBean接口。DynamicMBean写好后,使用方法和第一篇文章中普通的MBean一样。

package com.util.concurrent;
import java.lang.reflect.Constructor;
import java.util.Iterator;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.DynamicMBean;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ReflectionException;


public class HelloDynamic implements DynamicMBean {
    //这是我们的属性名称
    private String name;
    private MBeanInfo mBeanInfo = null;
    private String test;
    private String className;
    private String description;
    private MBeanAttributeInfo[] attributes;
    private MBeanConstructorInfo[] constructors;
    private MBeanOperationInfo[] operations;
    MBeanNotificationInfo[] mBeanNotificationInfoArray;

    public HelloDynamic() {
        init();
        buildDynamicMBean();
    }

    private void init() {
        className = this.getClass().getName();
        description = "Simple implementation of a dynamic MBean.";
        attributes = new MBeanAttributeInfo[2];
        constructors = new MBeanConstructorInfo[1];
        operations = new MBeanOperationInfo[1];
        mBeanNotificationInfoArray = new MBeanNotificationInfo[0];
    }

    private void buildDynamicMBean() {
        //设定构造函数
        Constructor[] thisconstructors = this.getClass().getConstructors();
        constructors[0] = new MBeanConstructorInfo("HelloDynamic(): Constructs a HelloDynamic object", thisconstructors[0]);
        //设定一个属性
        attributes[0] = new MBeanAttributeInfo("Name", "java.lang.String", "Name: name string.", true, true, false);
        attributes[1] = new MBeanAttributeInfo("Test", "java.lang.String", "Name: name string.", true, true, false);
        //operate method 我们的操作方法是print
        MBeanParameterInfo[] params = null;//无参数
        operations[0] = new MBeanOperationInfo("print", "print(): print the name", params, "void", MBeanOperationInfo.INFO);
        mBeanInfo = new MBeanInfo(className, description, attributes, constructors, operations, mBeanNotificationInfoArray);
    }

    //动态增加一个print1方法
    private void dynamicAddOperation() {
        init();
        operations = new MBeanOperationInfo[2];//设定数组为两个
        buildDynamicMBean();
        operations[1] = new MBeanOperationInfo("print1", "print1(): print the name", null, "void", MBeanOperationInfo.INFO);
        mBeanInfo = new MBeanInfo(className, description, attributes, constructors, operations, mBeanNotificationInfoArray);
    }

    public Object getAttribute(String attribute_name) {
        if (attribute_name != null)
            return null;
        if (attribute_name.equals("Name"))
            return name;
        if (attribute_name.equals("Test"))
            return test;
        return null;
    }

    public void setAttribute(Attribute attribute) {
        if (attribute == null)
            return;
        String Name = attribute.getName();
        Object value = attribute.getValue();
        try {
            if (Name.equals("Name")) {
                // if null value, try and see if the setter returns any exception
                if (value == null) {
                    name = null;
                    // if non null value, make sure it is assignable to the attribute
                } else if ((Class.forName("java.lang.String")).isAssignableFrom(value.getClass())) {
                    name = (String) value;
                }
            }
            if (Name.equals("Test")) {
                // if null value, try and see if the setter returns any exception
                if (value == null) {
                    test = null;
                    // if non null value, make sure it is assignable to the attribute
                } else if ((Class.forName("java.lang.String")).isAssignableFrom(value.getClass())) {
                    test = (String) value;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public AttributeList getAttributes(String[] attributeNames) {
        if (attributeNames == null)
            return null;
        AttributeList resultList = new AttributeList();
        // if attributeNames is empty, return an empty result list
        if (attributeNames.length == 0)
            return resultList;
        for (int i = 0; i < attributeNames.length; i++) {
            try {
                Object value = getAttribute(attributeNames[i]);
                resultList.add(new Attribute(attributeNames[i], value));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultList;
    }

    public AttributeList setAttributes(AttributeList attributes) {
        if (attributes == null)
            return null;
        AttributeList resultList = new AttributeList();
        // if attributeNames is empty, nothing more to do
        if (attributes.isEmpty())
            return resultList;
        // for each attribute, try to set it and add to the result list if successfull
        for (Iterator i = attributes.iterator(); i.hasNext();) {
            Attribute attr = (Attribute) i.next();
            try {
                setAttribute(attr);
                String name = attr.getName();
                Object value = getAttribute(name);
                resultList.add(new Attribute(name, value));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultList;
    }

    public Object invoke(String operationName, Object params[], String signature[]) throws MBeanException, ReflectionException {
        // Check for a recognized operation name and call the corresponding operation
        if (operationName.equals("print")) {
            //具体实现我们的操作方法print
            System.out.println("Hello, " + name + ", this is HellDynamic!");
            System.out.println("Hello, " + test + ", this is HellDynamic!");
            dynamicAddOperation();
            return null;
        } else if (operationName.equals("print1")) {
            System.out.println("这是动态增加的一方法print1");
            return null;
        } else {
            // unrecognized operation name:
            throw new ReflectionException(new NoSuchMethodException(operationName), "Cannot find the operation " + operationName + " in " + className);
        }

    }

    public MBeanInfo getMBeanInfo() {
        return mBeanInfo;
    }
}
package com.util.concurrent;

import com.sun.jdmk.comm.HtmlAdaptorServer;

import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
public class HelloAgent {
    public static void main(String[] args) throws Exception {
        MBeanServer server = MBeanServerFactory.createMBeanServer();
        ObjectName helloName = new ObjectName("chengang:name=HelloDynamic");
        HelloDynamic hello = new HelloDynamic();
        server.registerMBean(hello, helloName);
        ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8082");
        HtmlAdaptorServer adapter = new HtmlAdaptorServer();
        server.registerMBean(adapter, adapterName);
        adapter.start();
        System.out.println("start.....");
    }
}

其中的一种玩法

package com.test.jmx.modeler;

public class Hello{
    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);
    }
}

接下去就是最关键的描述文件(mbeans-descriptors.xml)了:

<?xml version="1.0" encoding="UTF-8" ?>
<mbeans-descriptors>
    <mbean name="Hello" description="the hello bean" domain="MyMBean" group="helloGroup" type="com.test.jmx.modeler.Hello">
        <attribute name="name" description="a name attribute" type="java.lang.String" writeable="true"/>
        <operation name="printHello" description="public void printHello()" impact="ACTION" returnType="void"/>
        <operation name="printHello" description="public void printHello(String whoName)" impact="ACTION" returnType="void">
        	<parameter name="whoName" description="method parameter of printHello" type="java.lang.String"></parameter> 
        </operation>
    </mbean>
</mbeans-descriptors>

描述文件的名字可以随意,最主要的是要和下面的HelloAgent.java对应起来。
通过这个xml文件的定义就描述了Model MBean所需要的metadata信息和一个基本的ModelMBean实现。
关于这个xml文件有几个需要说明的地方:

的属性classname,name,type:

  • name属性是每个MBean被Registry对象注册的对象名
  • type属性是真正被管理资源的全面(包括包名)
  • classname属性是用户扩展的用于实现代理功能的Model MBean的全名,如果不提供Modeler会使用
  • BaseModelMBean;如果提供了代理的ModelMBean对象,在使用时可以使用如下的代码样本访问他所代理的资源对象。

其余的标签就比较好理解了。综述:上面所示代码声明了一个Model MBean, 唯一标示是“Hello”,该MBean负责管理的对象是com.test.jmx.modeler.Hello的实例。域是MyMBean。这个MBean暴露了一个属性name和两个方法printHello()和printHello(String whoName).

下面是新的HelloAgent.java的代码:

package com.test.jmx.modeler;

import com.sun.jdmk.comm.HtmlAdaptorServer;
import org.apache.commons.modeler.ManagedBean;
import org.apache.commons.modeler.Registry;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.modelmbean.ModelMBean;
import java.io.InputStream;

public class HelloAgent  {
    public static void main(String[] args) throws Exception {
// 需要将xml信息读入到Registry对象中
        Registry registry = Registry.getRegistry(null,null);
        InputStream stream = HelloAgent.class.getResourceAsStream("mbeans-descriptors.xml");
        registry.loadMetadata(stream);
        MBeanServer server = registry.getMBeanServer();

// 之前是:MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        ManagedBean managed = registry.findManagedBean("Hello");
        ObjectName helloName = new ObjectName(managed.getDomain()+":name=HelloWorld");
// 以前是Hello hello = new Hello(); 为什么要多个createMBean?因为现在的写法没有写MBean,所以才要动态生成一个,以前就直接
// 把new hello()注册到MBeanServer就可以了,server会自动找到它的HelloMBean接口文件。
        ModelMBean hello = managed.createMBean(new Hello());
        server.registerMBean(hello,helloName);

        ObjectName adapterName = new ObjectName(managed.getDomain()+":name = htmladapter,port=8082");
        HtmlAdaptorServer adapter = new HtmlAdaptorServer();
        server.registerMBean(adapter,adapterName);
        adapter.start();
    }
}

​ 注意这里的Registry是指org.apache.commons.modeler.Registry,因为JMX自身也有一个Registry(java.rmi.registry.Registry)。通过Modeler组件提供的Registry对象,可以很方便的完成MBeanServer的创建。

Open MBeans

​ Open MBeans被设计为可以被更大范围的管理程序访问.

​ Open MBean使用通用的数据类型。 管理程序和Open MBeans就可以共享和使用数据和方法,而不需要重新编译,重新组配或者动态链接。所以说,Open MBeans提高了管理系统的灵活性和可扩展性。

	Open MBeans当管理程序无法访问agent的java classes的时候,就特别有用。即使管理程序和agent之间的连接不支持java序列化的时候,也是可以访问Open MBeans的。比如说,管理程序不是java开发的。
	 Open MBeans必须实现DynamicMBean接口,以对管理程序提供自我描述。与DynamicMBean的不同,就是Open MBean提供了更复杂的metadata数据,和在接口中,只使用了几种预定义的数据类型。
	判断一个MBean是不是open的,可以根据它返回的MBeanInfo对象来判断。Open MBean返回的是OpenMBeanInfo对象,这个类是MBeanInfo的子类。

Model MBean

​ 相对于Standard MBean,Model MBean更加灵活。如果我们不能修改已有的Java类,那么使用Model MBean是不错的选择。

​ Model MBean也是一种专门化的动态管理构件。它是预制的、通用的和动态的 MBean 类,已经包含了所有必要缺省行为的实现,并允许在运行时添加或覆盖需要定制的那些实现。JMX规范规定该类必须实现为javax.management.modelmbean.RequiredModelMBean,管理者要做的就是实例化该类,并配置该构件的默认行为并注册到JMX代理中,即可实现对资源的管理。JMX代理通过获得一个ModelMBeanInfo对象来获取管理接口。

模型管理构件具有以下新的特点:

  • 持久性。定义了持久机制,可以利用Java的序列化或JDBC来存储模型MBean的状态。 就是要保存到硬盘上。
  • 通知和日志功能。能记录每一个发出的通知,并能自动发出属性变化通知。
  • 属性值缓存。具有缓存属性值的能力。
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);
    }
}
package com.test.jmx.modelBean;


import javax.management.*;
import javax.management.modelmbean.*;

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 ModelMBeanInfo
        ModelMBeanInfo 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 优势之所在了。

MXBeans

​ 一个的MXBean是一种MBean的只引用一组预定义的数据类型。通过这种方式,您可以确保您的 MBean 可供任何客户端(包括远程客户端)使用,而无需客户端有权访问代表您的 MBean 类型的特定于模型的类。MXBean 提供了一种将相关值捆绑在一起的便捷方法,而无需专门配置客户端来处理这些捆绑包。

​ 与Standard MBean 的方式相同,MXBean 是通过编写一个被调用的 Java 接口SomethingMXBean和一个实现该接口的 Java 类来定义的。但是,与标准 MBean 不同,MXBean 不需要调用 Java 类Something。接口中的每个方法都定义了 MXBean 中的属性或操作。注释@MXBean也可用于注释 Java 接口,而不是要求接口名称后跟 MXBean 后缀。

package com.example; 
 
public interface QueueSamplerMXBean { 
    public QueueSample getQueueSample(); 
    public void clearQueue(); 
} 
package com.example; 
 
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; 
 
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; 
 
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 mxbeanName = new ObjectName("com.example: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, mxbeanName);
                 
        System.out.println("Waiting..."); 
        Thread.sleep(Long.MAX_VALUE); 
    } 
} 

如何定义MBean类

(1)直接实现MBean接口

(2)extend一个标准的MBean类:但是注意在子类中,只可以覆写父MBean的方法但是不可以添加新的方法,而且它必须自身提供一个public构造函数因为构造函数是不可以继承的。

(3)创建一个新的MBean接口让其extend一个老的MBean接口,并且让新的MBean类实现新的MBean接口

(4)创建一个新的MBean接口让其extend一个不是MBean接口的接口,并且让新的MBean类实现新的MBean接口。

MBean开发准则

(1)MBean必须是一个具体类(可以实例化的)

(2)MBean必须有public构造函数,可以有多个

(3)MBean必须实现自己的MBean接口(Standard MBean)或者DynamicBean接口 (Dynamic MBean)

此外,MBean可以可选的实现NotificationBroadcaster接口,如果这样做的话这个MBean就可以发送通知给有兴趣的监听器了。

JMX基本概念

受管资源(Manageable Resource)

​ 受管资源是任何应用,设备,实体,只要可以被Java访问或者被封装为Java对象的

那么谁来管这些受管资源呢?->MBean

MBean(Managed Bean)

​ MBean是在JMX规范中,满足命名规则和继承规范的Java类,它们可以用来操作和访问受管资源(通过一些属性和方法).MBean有3类(Standard,Dynamic,Model)

那么谁来管这些MBean呢?或者MBean生存在哪里呢?-> MBeanServer

MBean服务器(MBean Server)

​ MBeanServer是JMX规范中,用于管理一组MBean的Java类。所有的MBean被一视同仁的看待。MBeanServer向MBean暴露了一组用于管理MBean的接口,并且可以用于查询MBean

MBean要起作用,必须有一些底层服务支撑他们,这些服务就由JMXAgent提供

JMX代理(JMX Agent)

​ JMXAgent是一个Java进程,用于提供一组用来管理MBean组的服务。它是MBean服务器的容器。

那么,谁来和使用JMXAgent,谁来和JMXAgent交互呢?->协议适配器和连接器

协议适配器和连接器(Protocol Adaptors and Connectors)

​ 这些适配器和连接器是用于暴露JMXAgent给形形×××的协议或者客户端使用的中间桥梁。适配器(只存在在JMXAgent中),连接器(JMXAgent和客户端各有一个对象)

管理应用程序 (Management Application)

​ Management Application是对访问,配置,操作受管资源有兴趣的应用程序。典型的,比如JBoss中的jmx-console.

通知(Notification)

​ 通知是MBean或者MBeanServer发出的用于包含事件,断言或者通用信息的Java对象。MBean或者Java对象可以注册Listener来接收这些通知。

设备(Instrumentation)

​ 设备是使用MBean或者一组MBean来暴露受管资源的进程

JMX的架构

JMX采用的是3层的架构模型:

分配层:(Distributed Layer)

​ 这一层主要包含了能JMXAgent和外部世界进行通信的组件。有两种类型的交互,一种称为adaptor,一种称为connector.

代理层: (Agent Layer)

​ 这一层主要包含了Agent和MBeanServer,前者为了方便管理MBean,提供了4类服务(timer,monitoring,dynamic MBean loading,relationship service)。后者用于注册MBean,并且是JMX架构的核心组件。

设备层:(Instrumentation Layer)

​ 这一层主要包含了MBean,每个MBean可通过API来使用,或者,操作一个受管资源

Notification

​ 一个MBean提供的管理接口允许代理对其管理资源进行控制和配置。然而,对管理复杂的分布式系统来说,这些接口知识提供了一部分功能。通常,管理应用程序需要对状态变化或者当特别情况发生变化时作出反映。Notification起到了MBean之间的沟通桥梁的作用。JMX Notification模型和Java Event模型类似,将一些重要的信息,状态的转变,数据的变更传递给Notification Listener,以便资源的管理。
通知模型仅仅涉及了在同一个JMX代理中的管理构件之间的事件传播。JMX通知模型依靠以下几个部分:

  • Notification,一个通用的事件类型,该类标识事件的类型,可以被直接使用,也可以根据传递的事件的需要而被扩展。
  • NotificationListener接口,接受通知的对象需实现此接口。
  • NotificationFilter接口,作为通知过滤器的对象需实现此接口,为通知监听者提供了一个过滤通知的过滤器。
  • NotificationBroadcaster接口,通知发送者需实现此接口,该接口允许希望得到通知的监听者注册。

​ 发送一个通用类型的通知,任何一个监听者都会得到该通知。因此,监听者需提供过滤器来选择所需要接受的通知。任何类型的MBean,标准的或动态的,都可以作为一个通知发送者,也可以作为一个通知监听者,或两者都是。

package com.test.jmx.notification;

import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;

public class XiaoSi extends NotificationBroadcasterSupport implements XiaoSiMBean {

    private int seq = 0;
    /*
    * 必需继承NotificationBroadcasterSupport
    * 此类只有一个hi方法,方法只有两句:创建一个Notification消息包,然后将包发出去
    * 如果你还要在消息包上附加其他数据,Notification还有一个setUserData方法可供使用
     */
    @Override
    public void hi() {
        Notification n = new Notification(//创建一个信息包
                "xiaosi.hi",//给这个Notification起个名称
                this,//由谁发出的Notification
                ++seq,//一系列通知中的序列号,可以设置任意数值
                System.currentTimeMillis(),//发出时间
                "Xiaosi"//发出信息的消息文本
        );

        sendNotification(n);
    }
}
package com.test.jmx.notification;

public interface XiaoSiMBean {
    public void hi();
}

接下去创建Hello类的Listener(HelloListener.java),用于监听Notification的消息包并处理。

package com.test.jmx.notification;

import com.test.jmx.Hello;

import javax.management.Notification;
import javax.management.NotificationListener;

public class HelloListener implements NotificationListener {
    @Override
    public void handleNotification(Notification notification, Object handback) {
    	System.out.println("----------HelloListener-Begin------------");
        System.out.println("\ttype = "+ notification.getType());
        System.out.println("\tsource = "+notification.getSource());
        System.out.println("\tseq = "+notification.getSequenceNumber());
        System.out.println("\tsend time = "+notification.getTimeStamp());
        System.out.println("\tmessage="+notification.getMessage());
        System.out.println("----------HelloListener-End------------");

        if (handback != null) {
            if (handback instanceof Hello) {
                Hello hello = (Hello)handback;
                hello.printHello(notification.getMessage());
            }
        }
    }
}
package com.test.jmx.notification;

import com.sun.jdmk.comm.HtmlAdaptorServer;
import com.test.jmx.Hello;

import javax.management.*;
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();
        server.registerMBean(hello,helloName);

        ObjectName adapterName = new ObjectName("MyBean:name=htmladapter,port=8082");
        HtmlAdaptorServer adapter = new HtmlAdaptorServer();
        server.registerMBean(adapter,adapterName);

        XiaoSi xs = new XiaoSi();
        server.registerMBean(xs,new ObjectName("MyMBean:name=xiaosi"));
        xs.addNotificationListener(new HelloListener(),null,hello);
        adapter.start();
    }
}

辅助元数据类

​ 辅助元数据类用来描述管理构件。辅助元数据类不仅被用来内省标准管理构件,也被动态管理构件用来进行自我描述。这些类根据属性、操作、构建器和通告描述了管理接口。JMX代理通过这些元数据类管理所有管理构件,而不管这些管理构件的类型。部分辅助元类如下:

  • MBeanInfo–包含了属性、操作、构建器和通知的信息。
  • MBeanFeatureInfo–为下面类的超类。
  • MBeanAttributeInfo–用来描述管理构件中的属性。
  • MBeanConstructorInfo–用来描述管理构件中的构建器。
  • MBeanOperationInfo–用来描述管理构件中的操作。
  • MBeanParameterInfo–用来描述管理构件操作或构建器的参数。
  • MBeanNotificationInfo–用来描述管理构件发出的通知。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值