JMX/Java管理扩展

本文介绍了Java Management Extensions(JMX)的基本概念和架构,包括MBean、MBeanServer和不同类型的MBean。通过实例展示了如何使用HTTP适配器、RMI连接器以及HTML适配器与动态MBean进行实践操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. JMX介绍

JMX是Java Management Extensions的缩写,意为Java管理扩展,是一个标准也是一个框架,用来监控和管理JVM上面的资源,例如我们用jvisualvm监控远程的JVM时,远程需要开启JMX

1.1 JMX架构

JMX作为一个标准和框架,要实现JMX编程必须基于其架构,架构就是与其相关的一些概念或架构分层;

JMX有一个MBean / 管理组件的概念,MBean是Management Bean的缩写,是对JVM上面所有资源的抽象,MBean作为一种Java对象,可以通过MBean的属性和方法访问JVM上面的各种资源;

JMX的架构由 分布层代理层设备层 组成;

  设备层/MBean:将所有资源抽象成MBean组件,通过MBean访问资源,共有4类MBean,通常接触的都是标准MBean:

  1. 标准MBean:StdMBean接口描述行为,Std类实现行为; 要求:①接口和类必须在一个包下 ②接口名MBean结尾,实现类名为接口名前半部分;
  2. 动态MBean:实现DynamicMBean接口,接口中getMBeanInfo方法返回的MBeanInfo包含有哦此MBean暴露的所有属性(MBeanAttitudeInfo)和方法(MBeanOperationInfo),此MBeanInfo可以动态扩展;
  3. 开放MBean:忽略
  4. 模型MBean:忽略
  5. MXBean:MyMXBean接口描述行为,实现类实现行为且类名随意,要求:接口名MBean结尾或者接口用@MXBean注解;

  代理层/MBeanServer:存放MBean组件的容器,提供注册和请求MBean的功能,容器就是管理组件服务器 / MBeanServer,创建管理组件服务器时需要制定服务器的域名,当向管理组件服务器注册管理组件时需要指定一个ObjectName对象来标识管理组件,ObjectName对象由域名和键值对列表构成,域名就是创建管理组件服务器的域名,键值对用来区分不同的MBean至少有一对且一般有name=XXX;

  分布层:管理客户端如何访问管理组件服务器中的管理组件,有协议适配器连接器两种实现形式,而适配器和连接器也作为一种MBean注册到管理组件服务器,常见的就是HTML适配器和RMI连接器,HTML适配器可以用浏览器客户端访问,RMI连接器可以用JConsole客户端访问;

1.2 JMX编程元素

编程元素就是如何按照JMX架构提供的规范来编写代码,JMX编程一般分为编写管理组件和编写管理组件服务器;

管理组件:包括设备层和分布层,分布层的适配器和连接器组件不需要自己编写,引入jar包即可,所以一般指编写自定义的管理组件,一般是标准MBean;

管理组件服务器:指代理层,分为三步,创建管理组件服务器,创建并注册自定义管理组件,创建并注册协议适配器或连接器组件;

2. JMX API

3. 实例

3.1 HTTP适配器

实例用标准MBean和Html适配器实现,MBean暴露了name属性,

Html适配器相关类不在jdk中,需要单独引入jar包;  

自定义(标准)管理组件-接口:WorkerMBean

/**
 * 管理组件接口
 */
public interface WorkerMBean {
    String getName();
}

  自定义(标准)管理组件-实现类:Worker

/**
 * 管理组件实现类
 */
public class Worker implements WorkerMBean {
    @Override
    public String getName() {
        return "kepus";
    }
}

  管理组件服务器:HtmlAdaptorAgent

需要引入的 jar 包

import com.sun.jdmk.comm.HtmlAdaptorServer;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;

/**
 * 代理层/管理组件服务器:客户端通过http访问管理组件服务器
 */
public class HtmlAdaptorAgent {

    // 域名
    private static final String DOMAIN = "gc";

    public static void main(String[] args) throws Exception {

        //用指定域名创建管理组件服务器
        MBeanServer mBeanServer = MBeanServerFactory.createMBeanServer(DOMAIN);

        // 创建自定义管理组件 -> 创建管理组件标识 -> 注册管理组件到管理组件服务器
        Worker worker = new Worker();
        //对象名用于标识不同MBean,由域名和键值对构成,键值对之间用逗号隔开
        ObjectName objName4Worker = new ObjectName(DOMAIN + ":name=worker, creator=gongcong");
        mBeanServer.registerMBean(worker, objName4Worker);

        // 创建适配器管理组件 -> 创建管理组件标识 -> 注册适配器管理组件到管理组件服务器 -> 启动适配器
        HtmlAdaptorServer htmlAdaptorServer = new HtmlAdaptorServer();
        ObjectName objectName4Adaptor = new ObjectName(DOMAIN + ":name=htmlAdaptorServer, listenPort=8082");
        mBeanServer.registerMBean(htmlAdaptorServer, objectName4Adaptor);
        htmlAdaptorServer.start();

        System.out.println("jmx started plz access in browser using http://localhost:8082");
    }
}

运行结果:浏览器访问 http://localhost:8082/

 

3.2 RMI连接器

实例用MXBean和RMI连接器实现,MBean暴露了name属性,

自定义(MXBean)管理组件-接口:Worker

import javax.management.MXBean;

/**
 * 管理组件接口
 */
@MXBean
public interface Worker {
    String getName();
}

自定义(MXBean)管理组件-实现类:WorkerImpl

/**
 * 管理组件实现类
 */
public class WorkerImpl implements Worker {
    @Override
    public String getName() {
        return "angular";
    }
}

管理组件服务器:RMIConnectorAgent

import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import java.rmi.registry.LocateRegistry;

/**
 * 代理层/管理组件服务器: 通过客户端通过rmi协议访问管理组件服务器
 */
public class RMIConnectorAgent {

    // 域名
    private static final String DOMAIN = "cg";

    public static void main(String[] args) throws Exception {

        //用指定域名创建管理组件服务器
        MBeanServer mBeanServer = MBeanServerFactory.createMBeanServer(DOMAIN);

        // 创建自定义管理组件 -> 创建管理组件标识 -> 注册管理组件到管理组件服务器
        WorkerImpl worker = new WorkerImpl();
        ObjectName objectName4Person = new ObjectName(DOMAIN, "name", "worker");
        mBeanServer.registerMBean(worker, objectName4Person);

        //创建RMI注册表
        LocateRegistry.createRegistry(41440);

        /*
            创建JMX管理组件服务器地址
            service:jmx 为JMX URL前缀
            :rmi://127.0.0.1:41441 表示rmi连接器;127.0.0.1为JMX管理组件服务器地址,可省略;41441为端口,可省略,省略是为随机
            jndi/rmi://127.0.0.1:41440/cg 表示 管理组件服务器 在RMI注册表中的位置
         */
        JMXServiceURL jmxServiceURL = new JMXServiceURL
                ("service:jmx:rmi://127.0.0.1:41441/jndi/rmi://127.0.0.1:41440/cg");
        //创建RMI连接器组件并注册到管理组件服务器
        JMXConnectorServer jmxConnectorServer = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, null,
                mBeanServer);
        // 启动连接器
        jmxConnectorServer.start();

        System.out.println("jmx started plz access " +
                "use JConsole use service:jmx:rmi://127.0.0.1:41441/jndi/rmi://127.0.0.1:41440/cg");
    }
}

运行结果:通过jdk自带的 jconsole.exe 访问

远程进程中的地址为:service:jmx:rmi://127.0.0.1:41441/jndi/rmi://127.0.0.1:41440/cg

3.3 HTML适配器+动态MBean

自定义动态管理组件:Worker

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ReflectionException;
import java.util.ArrayList;
import java.util.List;

/**
 * 动态MBean,MBean暴露的属性和接口可以动态扩展
 */
public class Worker implements DynamicMBean {

    // 暴露的属性列表
    private List<String> lstExposedAttribute;

    public Worker() {
        this.lstExposedAttribute = new ArrayList<>();
        // 默认暴露id 和 name
        lstExposedAttribute.add("id");
        lstExposedAttribute.add("name");
    }

    /**
     * 获取此MBean暴露的属性和方法
     */
    @Override
    public MBeanInfo getMBeanInfo() {

        // MBean类名
        String className = this.getClass().getName();

        // MBean的描述
        String mbeanDescription = "this is dynamic mbean";

        // 暴露的属性
        MBeanAttributeInfo[] attributeInfos = new MBeanAttributeInfo[lstExposedAttribute.size()];
        for (int i = 0; i < lstExposedAttribute.size(); i++) {
            String attributeName = lstExposedAttribute.get(i);
            attributeInfos[i] = new MBeanAttributeInfo(attributeName, "String", "exposed " +
                    "attribute " + attributeName, true, true, false);

        }

        // 暴露的方法:新增暴露属性
        MBeanOperationInfo[] mBeanOperationInfos = new MBeanOperationInfo[1];
        MBeanParameterInfo[] parameterInfos = new MBeanParameterInfo[]{new MBeanParameterInfo("attributeName",
                "String", "new Attribute")};
        mBeanOperationInfos[0] = new MBeanOperationInfo("addAttribute", "add new attribute", parameterInfos,
                "void", MBeanOperationInfo.ACTION);

        return new MBeanInfo(className, mbeanDescription, attributeInfos, null, mBeanOperationInfos,
                null);
    }

    /**
     * 暴露的属性的值都是通过此方法获取
     */
    @Override
    public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException,
            ReflectionException {
        return attribute + "'s value";
    }

    // 页面点击暴露的方法会调到此处
    @Override
    public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException,
            ReflectionException {
        if (actionName.equalsIgnoreCase("addAttribute")) {
            this.lstExposedAttribute.add(((String) params[0]));
            return "add " + params[0] + " success";
        }
        return null;
    }

    // 通过页面设置属性值:没实现,调用会抛出异常
    @Override
    public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException,
            MBeanException, ReflectionException {
    }

    // 通过页面设置属性值:没实现,调用会抛出异常
    @Override
    public AttributeList setAttributes(AttributeList attributes) {
        return null;
    }

    @Override
    public AttributeList getAttributes(String[] attributes) {
        return null;
    }

}

管理组件服务器:HtmlAdaptorAgent

需要引入的 jar 包

import com.sun.jdmk.comm.HtmlAdaptorServer;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;

/**
 * 代理层/管理组件服务器:客户端通过http访问管理组件服务器
 */
public class HtmlAdaptorAgent {

    // 域名
    private static final String DOMAIN = "gg";

    public static void main(String[] args) throws Exception {

        //用指定域名创建管理组件服务器
        MBeanServer mBeanServer = MBeanServerFactory.createMBeanServer(DOMAIN);

        // 创建自定义管理组件 -> 创建管理组件标识 -> 注册管理组件到管理组件服务器
        Worker worker = new Worker();
        //对象名用于标识不同MBean,由域名和键值对构成,键值对之间用逗号隔开
        ObjectName objName4Worker = new ObjectName(DOMAIN + ":name=worker");
        mBeanServer.registerMBean(worker, objName4Worker);

        // 创建适配器管理组件 -> 创建管理组件标识 -> 注册适配器管理组件到管理组件服务器 -> 启动适配器
        HtmlAdaptorServer htmlAdaptorServer = new HtmlAdaptorServer();
        ObjectName objectName4Adaptor = new ObjectName(DOMAIN + ":name=htmlAdaptorServer, listenPort=8082");
        mBeanServer.registerMBean(htmlAdaptorServer, objectName4Adaptor);
        htmlAdaptorServer.start();

        System.out.println("jmx started plz access in browser using http://localhost:8082");
    }
}

运行结果:浏览器访问 http://localhost:8082/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值