Java8之JMX与MBean

news2024/9/24 1:22:40

参考文章:

《JMX超详细解读》

《JMX》

        写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。

        在学习tomcat源码架构的时候了解到其中使用了JMX来实现一些管理工作,于是便整理了这篇文章出来。

目录

一、JMX入门

        1、JMX概念

        2、JMX的架构

        1、基础层

        2、适配层

        3、接入层

二、JMX的使用

        1、使用Jconsole访问

        1.1、资源注册

        1.2、启动监控

        2、通过JMX提供的工具页访问

         3、通过客户端程序进行远程访问

三、补充

        常用的 MBean


一、JMX入门

        1、JMX概念

        JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架。JMX是一套标准的代理和服务,实际上,用户可以在任何Java应用程序中使用这些代理和服务实现管理。

        个人理解其实就是Java 管理扩展,用来管理和监测 Java 程序。最常用到的就是对于 JVM 的监测和管理,比如 JVM 内存、CPU 使用率、线程数、垃圾收集情况等等。

        比如${JAVA_HOME}的/bin目录下的jconsole,正式利用的JMX实现的资源监控。

        2、JMX的架构

        整个架构可以由底向上分为基础层(探测层)、适配层(代理层)、接入层(远程管理层),下面我们来分别介绍下。

        1、基础层

        这其中主要是被管理的资源MBean,MBean主要有四种,Standard MBean、Dynamic MBean、Open MBean、Model MBean,源码主要在 java.lang.management 和 javax.management包里面。

        Standard MBean这种类型的MBean最简单,它能管理的资源(包括属性,方法,时间)必须定义在接口中,然后MBean必须实现这个接口。它的命名也必须遵循一定的规范,例如我们的MBean为Hello,则接口必须为HelloMBean。

        Dynamic MBean必须实现javax.management.DynamicMBean接口,所有的属性,方法都在运行时定义。另外还有两类 MBean:Open MBean 和 Model MBean,实际上它们也都是动态 MBean。

        2、适配层

        MBeanServer 是负责管理 MBean 的,一般一个 JVM 只有一个 MBeanServer,所有的 MBean 都要注册到 MBeanServer 上,并通过 MBeanServer 对外提供服务。一般用 ManagementFactory.getPlatformMBeanServer()方法获取当前 JVM 内的 MBeanServer。

        3、接入层

          写好的 MBean 注册到 MBeanServer 上之后,功能已经具备了。适配器和连接器就是将这些功能开放出来的方式。比如  HTTP协议适配器,就是将功能以 HTTP 协议开放出去,这样我们就可以在浏览器使用了。但是 JDK 只是提供了适配器的实现标准,并没有具体的实现,比较常用的是 HtmlAdaptorServer,需要 jmxtools.jar 包的支持。

二、JMX的使用

        以下内容参考自《JMX超详细解读》

        1、使用Jconsole访问

        1.1、资源注册

        首先定义一个MBean接口,接口的命名规范为以具体的实现类为前缀

public interface HelloMBean
{
     public String getName();

     public void setName(String name);

     public String getAge();

     public void setAge(String age);

     public void helloWorld();

     public void helloWorld(String str);

     public void getTelephone();
}

        然后定义一个实现类,实现上面的接口:

/*
  * 该类名称必须与实现的接口的前缀保持一致(即MBean前面的名称
  */
 public class Hello implements HelloMBean
 {
     private String name;
         
     private String age;
 
     public void getTelephone()
     {
         System.out.println("get Telephone");
     }
 
     public void helloWorld()
     {
         System.out.println("hello world");
     }
 
     public void helloWorld(String str)
     {
         System.out.println("helloWorld:" + str);
     }
 
     public String getName()
     {
         System.out.println("get name 123");
         return name;
     }
 
     public void setName(String name)
     {
         System.out.println("set name 123");
         this.name = name;
     }
 
     public String getAge()
     {
         System.out.println("get age 123");
         return age;
     }
 
     public void setAge(String age)
     {
         System.out.println("set age 123");
         this.age = age;
     }      
 }

        最后进行注册,实现代理层

import java.lang.management.ManagementFactory;

import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.ObjectName;

public class HelloAgent
{
    public static void main(String[] args) throws JMException, Exception
    {
         // 通过工厂类获取MBeanServer,用来做MBean的容器
         MBeanServer server = ManagementFactory.getPlatformMBeanServer();
         // 创建一个ObjectName对象,注意取名规范
         // 格式为:“域名:name=MBean名称”,域名和MBean的名称可以任意
         ObjectName helloName = new ObjectName("jmxBean:name=hello");
         // 将Hello这个类注入到MBeanServer中
         server.registerMBean(new Hello(), helloName);
         Thread.sleep(60*60*1000);
    }
}

        这样,一个简单的JMX的DEMO已经写完了,现在我们通过JDK提供的Jconsole来进行操作。

        1.2、启动监控

        JConsole 是 JDK 自带的工具,在${JAVA_HOME}的 bin 目录下,启动即可。

         启动JConsole后可以看到会显示本地的java进程,包括我们正在运行的HelloAgent与JConsole本身。

                         

        打开我们的本地进程HelloAgent,点击属性会自动调用get方法:

        在这个界面上,我们可以调用其中的方法来给属性赋值

          注意ObjectName中的取名是有一定规范的,格式为:“域名:name=MBean名称”,其中域名和MBean的名称可以任意取。这样定义后,就可以唯一标识我们定义的这个MBean的实现类了。

       2、通过JMX提供的工具页访问

        复用上面的接口和实现类,只需要改动适配层,这里需要到导入外部jar包jdmk,注册工具页面访问适配器,而这个适配器本身也是个MBean 。

package jmx;

import java.lang.management.ManagementFactory;

import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.ObjectName;

import com.sun.jdmk.comm.HtmlAdaptorServer;

public class HelloAgent
{
    public static void main(String[] args) throws JMException, Exception
    {
         MBeanServer server = ManagementFactory.getPlatformMBeanServer();
         ObjectName helloName = new ObjectName("jmxBean:name=hello");
         //create mbean and register mbean
         server.registerMBean(new Hello(), helloName);
         
         ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8082");  
         // 注册工具页面访问适配器,不难发现这也是个MBean 
         HtmlAdaptorServer adapter = new HtmlAdaptorServer();   
         server.registerMBean(adapter, adapterName);  
         adapter.start();
    }
}

         如果缺少HtmlAdaptorServer类的可以在pom里添加jmxtools的引用。

    <dependency>
    	<groupId>com.sun.jdmk</groupId>
    	<artifactId>jmxtools</artifactId>
   	 	<version>1.2.1</version>
	</dependency>

        代理类运行后就可以通过地址http://localhost:8082来访问管路页面

         点击name=hello,就进入到了hello这个MBean的管理页面,这里提供了与JConsole类似的管理功能。

         3、通过客户端程序进行远程访问

        这里需要对agent进行修改,增加ip和porta绑定部分的逻辑

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;

import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

public class HelloAgent
{
    public static void main(String[] args) throws JMException, NullPointerException
    {
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        ObjectName helloName = new ObjectName("jmxBean:name=hello");
        //create mbean and register mbean
        server.registerMBean(new Hello(), helloName);
        try
        {
            //这个步骤很重要,注册一个端口,绑定url后用于客户端通过rmi方式连接JMXConnectorServer
            LocateRegistry.createRegistry(9999);
            //URL路径的结尾可以随意指定,但如果需要用Jconsole来进行连接,则必须使用jmxrmi
            JMXServiceURL url = new JMXServiceURL
                  ("service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi");
            JMXConnectorServer jcs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, server);
            System.out.println("begin rmi start");
            jcs.start();
            System.out.println("rmi start");
        }
        catch (RemoteException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
          }}

         如果没有client进行远程连接,可以使用Jconsole进行远程访问:

                ​​​​​​​        ​​​​​​​        

         当然我们也可以自己写一个客户端Client程序,用于与agent进行远程连接:

import java.io.IOException;

import javax.management.Attribute;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;


public class Client
{
    public static void main(String[] args) throws IOException, Exception, NullPointerException
    {
        JMXServiceURL url = new JMXServiceURL
            ("service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi");
        JMXConnector jmxc = JMXConnectorFactory.connect(url,null);

        MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
        //ObjectName的名称与前面注册时候的保持一致
        ObjectName mbeanName = new ObjectName("jmxBean:name=hello");

        System.out.println("Domains ......");
        String[] domains = mbsc.getDomains();

        for(int i=0;i<domains.length;i++)
        {
            System.out.println("doumain[" + i + "]=" + domains[i] );
        }

        System.out.println("MBean count = " + mbsc.getMBeanCount());
        //设置指定Mbean的特定属性值
        //这里的setAttribute、getAttribute操作只能针对bean的属性
        //例如对getName或者setName进行操作,只能使用Name,需要去除方法的前缀
        mbsc.setAttribute(mbeanName, new Attribute("Name","杭州"));
        mbsc.setAttribute(mbeanName, new Attribute("Age","1990"));
        String age = (String)mbsc.getAttribute(mbeanName, "Age");
        String name = (String)mbsc.getAttribute(mbeanName, "Name");
        System.out.println("age=" + age + ";name=" + name);

        HelloMBean proxy = MBeanServerInvocationHandler.
            newProxyInstance(mbsc, mbeanName, HelloMBean.class, false);
        proxy.helloWorld();
        proxy.helloWorld("migu");
        proxy.getTelephone();
        //invoke调用bean的方法,只针对非设置属性的方法
        //例如invoke不能对getName方法进行调用
        mbsc.invoke(mbeanName, "getTelephone", null, null);
        mbsc.invoke(mbeanName, "helloWorld",
            new String[]{"I'll connect to JMX Server via client2"}, new String[]{"java.lang.String"});
        mbsc.invoke(mbeanName, "helloWorld", null, null);
    }
}

         对资源里面的方法进行操作有两种方式:一是通过代理直接调用方法;二是通过JAVA的反射注入的方式进行方法的调用。

三、补充

        常用的 MBean

         有些指标是监控会用到的,比如内存、CPU、堆空间、线程、类加载情况相关的 MBean。
JDK 提供了一个 ManagementFactory,帮助我们方便的获取常用的 MBean。可以到 java.lang.management 包下找到这个类看一下注释和代码。

        OperatingSystemMXBean

        可以获取操作系统相关的信息,机器名称、内存使用、CPU使用等信息。可通过 ManagementFactory.getOperatingSystemMXBean() 方式获取。

        RuntimeMXBean

        可以获取当前 JVM 的信息,包括 JVM 参数和 JVM 相关的系统参数。可以通过 ManagementFactory.getRuntimeMXBean()方式获取。

        MemoryMXBean

        可以获取当前 JVM 的内存使用,包括堆内存和非堆内存。可以通过 ManagementFactory.getMemoryMXBean()获取。

        ThreadMXBean

        获取 JVM 线程使用情况,包括活动线程、守护线程、线程峰值等。可以通过 ManagementFactory.getThreadMXBean() 获取。

        ClassLoadingMXBean

        获取 JVM 类加载情况,包括已加载类、未加载类等。可以通过 ManagementFactory.getClassLoadingMXBean() 获取。

        GarbageCollectorMXBean

        获取 JVM 垃圾收集器的情况,包括使用的哪种垃圾收集器以及回收次数等等。可以通过 ManagementFactory.getGarbageCollectorMXBeans() 获取,注意,这里获取到的是一个集合,因为垃圾收集器分为老年代和新生代两个。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/98370.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux systemd-run unit封装CGroup资源进行任务运行

Linux systemd-run 封装资源使用 序 之前我们讲了关于 systemctl 对各种服务或者说是 unit 进行了讲解&#xff0c;也讲了怎么创建一个 unit&#xff0c;进行相关配置或者依赖设置等等。在使用 systemctl status xxx 时&#xff0c;我们可以发现对应的资源使用情况&#xff0…

JSTL标签库 | 深入解析JSTL标签库

目录 一&#xff1a;深入解析JSTL标签库 1、什么是JSTL标签库 2、使用JSTL标签库的步骤 3、JSTL标签的原理 4、jstl中的核心标签库core当中常用的标签 一&#xff1a;深入解析JSTL标签库 1、什么是JSTL标签库 ①Java Standard Tag Lib&#xff08;Java标准的标签库&am…

电脑文件不小心删除了怎么恢复 ? 删除的文件如何恢复文件?

如果误删电脑文件后&#xff0c;如何恢复文件&#xff1f; 电脑删除文件是很经常的事&#xff0c;为了电脑运行更快我们经常都会清理&#xff0c;但是有时候也会出现不小心删除重要文件的情况。如何恢复删除的文件&#xff1f;本文总结的2种常用方法可以帮助到你。 方法1、注册…

惠普CP1025 因转印离合器导致打印不全大片空白的问题

问题症状 自检只打印出一部分, 后面大部分都是空白. 如果是碳盒缺粉, 应该是均匀地浅或者空白, 如果是成像鼓的问题, 应该是从上到下成条状的不均匀, 这样显示一节后空白的情况是没见过, 上网查有类似的问题 惠普CP1025彩色激光打印机打印图像前半部有字后半部白纸惠普1025打印…

Java框架:Spring框架

文章目录一、Spring概念二、Spring特征三、Spring基本架构3.1Spring体系结构3.2Core Container(核心容器)3.3Data Access/Integration(数据访问/集成)3.4Web(MVC/Remoting)3.5Test(测试)3.6AOP(面向切面编程)四、Spring主要jar包五、Spring用到的设计模式一、Spring概念 什么是…

vue学习笔记(三)-组件化编程基础

概念 传统方式与组件化对比 存在问题 1.依赖关系混乱 2.代码复用率不高 模块与组件、模块化与组件化的关系 模块 a.理解&#xff1a;向外提供特定功能的 js 程序&#xff0c;一般就是一个 js 文件 b.为什么&#xff1a;js 文件很多很复杂 c.作用&#xff1a;复用、简化 …

【Docker技术内幕】(十二)使用docker安装Kafka

目录 一、准备工作 1、安装docker 2、设置加速镜像 二、开始安装 1、启动容器 三、验证Kafka是否安装成功 四、部署kafka-manager 一、准备工作 1、安装docker 参考 【Docker技术内幕】&#xff08;四&#xff09;Linux环境下安装docker 2、设置加速镜像 vim /etc/do…

C语言 数据存储 char int 数据存储 关于原码反码补码

上图 前五个整形是整形家族&#xff0c;为什么char也是 因为他是字符型 字符实际存储的时候寸的是这个的ascll值 ascll值是个整数 除了以上两种 还有构造类型 又叫自定义类型 为什么又数组类型 如下代码 arr和【】的内容都可以自定义 为什么出现以上情况.(ffff 是16进制表示…

第二证券|通过磁铁制造功率更大的电动汽车电池

德克萨斯大学奥斯汀分校的研讨人员表明&#xff0c;一个更厚的电极&#xff0c;经过磁优化的离子道路&#xff0c;能够使充电更快&#xff0c;充电之间的功率更大。 研讨人员制作了一种具有‘快速通道’摆放的电极&#xff0c;以进步充电速度和续航路程。 研讨人员发现了一种共…

Apache Hudi 数据湖介绍

目录​​​​​​​ Apache Hudi 数据湖介绍 Hudi 历程 Hudi Features Apache Hudi 数据湖介绍 Apache Hudi&#xff08;发音为“hoodie”&#xff09;是下一代流媒体数据湖平台源于Uber 。Apache Hudi将核心仓库和数据库功能直接引入数据湖。Hudi提供了表、事务、高效的追加…

[附源码]Nodejs计算机毕业设计基于云数据库的便民民宿租赁系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

人人都能看懂的Spring底层原理,看完绝对不会懵逼

人人都能看懂的Spring原理&#xff0c;绝对不会懵逼为什么要使用Spring&#xff1f;Spring的核心组件Spring是如何实现IOC和DI的&#xff1f;定义了BeanDefinition扫描加载BeanDefinition根据BeanDefinition进行Bean的实例化和初始化实例化属性赋值保存到单例缓冲池一个Bean从创…

docker高级篇2-分布式存储之三种算法

面试题&#xff1a; 1~2亿条数据需要缓存&#xff0c;请问如何设计这个缓存案例&#xff1f; 答&#xff1a;单机单台100%是不可能的。肯定是分布式缓存的。那么用Redis如何落地&#xff1f; 一般有三种方案&#xff1a; 哈希取余分区&#xff1b;一致性哈希算法分区&#…

HttpRunner4.x 安装与使用

HttpRunner4.x 安装与使用HttpRunner4.x 安装与使用安装使用运行脚手架项目方式一&#xff1a;录制生成用例步骤1&#xff1a;导出har文件步骤2&#xff1a;转化成测试用例文件步骤3&#xff1a;执行测试用例方式二&#xff1a;手工编写测试用例HttpRunner4.x 安装与使用 以下…

卡塔尔世界杯终局之战,阿根廷VS法国,是老将加冕还是新王登基?

【世界杯】阿根廷VS法国 不知不觉&#xff0c;世界杯已经走到最后的尾声&#xff0c;此前经历的28天&#xff0c;63场比赛皆是铺垫&#xff0c;卢赛尔体育场将会迎来2022卡塔尔世界杯最终的决赛&#xff0c;究竟是梅西球王加冕还是法国卫冕世界杯冠军&#xff0c;今晚23&#x…

KNN算法 鸢尾花种类预测

目录 一&#xff1a;KNN原理 二&#xff1a;数据处理 三&#xff1a;超参调试、模型保存及使用 四&#xff1a;鸢尾花种类预测 详细步骤 一&#xff1a;KNN原理 从训练集中找到跟待测数据最近的k条记录 根据这些记录的分类决定新数据的分类 主要因素包括有&#xff1a;K邻…

java------JVM之类加载和双亲委派机制

类加载器&#xff1a;加载.class文件。 将新建的对象放入堆里面&#xff0c;而对象的引用(地址)放到栈&#xff0c;其中引用指向堆里面对应的对象。 1-启动类加载器&#xff0c;负责加载jre\lib目录下的rt.jar包c编写&#xff0c;加载java核心库 java.*,构造ExtClassLoader和A…

[CocosCreator]封装行为树(一)

(老规矩:广告位留给自己) 欢迎喜欢或者从事CocosCreator开发的小伙伴请加入我的大家庭CocosCreator游戏开发Q群:26855530 行为树的定义:控制AI实体决策流程的分层节点树。游戏中Npc的活动,或者主角挂机行为都十分依赖行为树,本章开始,封装适用CococCreator使用的TypeScript行…

Mongo基本操作

文章目录核心概念库<DataBase>集合<Collection>文档<Document>MySQL与MongoDB关系总结基本操作库<database>集合<Collection>文档<document>文档查询ANDORAND 和 OR 联合模糊查询排序分页总条数去重指定返回字段索引<index>操作复合…

vmware ESXI 7 升级ESXI 8

1 、上传VMware-Esxi-8.0安装包 2开启ssh 3、 远程登录到Esxi主机 ssh root192.168.31.119 [rootlocalhost:~] 4、升级到Esxi 8.0 [rootlocalhost:~] esxcli software sources profile list -d /vmfs/volumes/datastore1/iso/VMware-ESXi-8.0-20513097-depot.zip Name Vend…