• JMX JMX(Java Management Extensions)定义


    一、JMX简介

    参考:https://honeypps.com/java/jmx-quick-start-1-standard-mbean/

    JMX的全称为Java Management Extensions. 顾名思义,是管理Java的一种扩展。这种机制可以方便的管理、监控正在运行中的Java程序。常用于管理线程,内存,日志Level,服务重启,系统环境等。

    基本术语

    • MBean:是Managed Bean的简称,可以翻译为“管理构件”。在JMX中MBean代表一个被管理的资源实例,通过MBean中暴露的方法和属性,外界可以获取被管理的资源的状态和操纵MBean的行为。事实上,MBean就是一个Java Object,同JavaBean模型一样,外界使用自醒和反射来获取Object的值和调用Object的方法,只是MBean更为复杂和高级一些。MBean通过公共方法以及遵从特定的设计模式封装了属性和操作,以便暴露给管理应用程序。例如,一个只读属性在管理构件中只有Get方法,既有Get又有Set方法表示是一个可读写的属性。一共有四种类型的MBean: Standard MBean, Dynamic MBean, Open MBean, Model MBean。
    • MBeanServer:MBean生存在一个MBeanServer中。MBeanServer管理这些MBean,并且代理外界对它们的访问。并且MBeanServer提供了一种注册机制,是的外界可以通过名字来得到相应的MBean实例。
    • JMX Agent:Agent只是一个Java进程,它包括这个MBeanServer和一系列附加的MbeanService。当然这些Service也是通过MBean的形式来发布。
    • Protocol Adapters and Connectors:MBeanServer依赖于Protocol Adapters和Connectors来和运行该代理的Java虚拟机之外的管理应用程序进行通信。Protocol Adapters通过特定的协议提供了一张注册在MBeanServer的MBean的视图。例如,一个HTML Adapter可以将所有注册过的MBean显示在Web 页面上。不同的协议,提供不同的视图。Connectors还必须提供管理应用一方的接口以使代理和管理应用程序进行通信,即针对不同的协议,Connectors必须提供同样的远程接口来封装通信过程。当远程应用程序使用这个接口时,就可以通过网络透明的和代理进行交互,而忽略协议本身。Adapters和Connectors使MBean服务器与管理应用程序能进行通信。因此,一个代理要被管理,它必须提供至少一个Protocol Adapter或者Connector。面临多种管理应用时,代理可以包含各种不同的Protocol Adapters和Connectors。当前已经实现和将要实现的Protocol Adapters和Connectors包括: RMI Connector, SNMP Adapter, IIOP Adapter, HTML Adapter, HTTP Connector.

    Adapter 和Connector的区别在于:Adapter是使用某种Internet协议来与JMX Agent获得联系,Agent端会有一个对象 (Adapter)来处理有关协议的细节。比如SNMP Adapter和HTTP Adapter。而Connector则是使用类似RPC的方式来访问Agent,在Agent端和客户端都必须有这样一个对象来处理相应的请求与应答。比如RMI Connector。

    JMX Agent可以带有任意多个Adapter,因此可以使用多种不同的方式访问Agent。

    JMX基本构架

    JMX分为三层,分别负责处理不同的事务。它们分别是:

    • Instrumentation 层
      Instrumentation层主要包括了一系列的接口定义和描述如何开发MBean的规范。通常JMX所管理的资源有一个或多个MBean组成,因此这个资源可以是任何由Java语言开发的组件,或是一个JavaWrapper包装的其他语言开发的资源。
    • Agent 层
      Agent 用来管理相应的资源,并且为远端用户提供访问的接口。Agent层构建在Intrumentation层之上,并且使用并管理 Instrumentation层内部描述的组件。Agent层主要定义了各种服务以及通信模型。该层的核心是一MBeanServer,所有的MBean都要向它注册,才能被管理。注册在MBeanServer上的MBean并不直接和远程应用程序进行通信,他们通过协议适配器(Adapter)和连接器(Connector)进行通信。通常Agent由一个MBeanServer和多个系统服务组成。JMX Agent并不关心它所管理的资源是什么。
    • Distributed 层
      Distributed层关心Agent如何被远端用户访问的细节。它定义了一系列用来访问Agent的接口和组件,包括Adapter和Connector的描述。

    如果一个Java对象可以由一个遵循JMX规范的管理器应用管理,那么这个Java对象就可以由JMX管理资源。要使一个Java对象可管理,则必须创建相应的MBean对象,并通过这些MBean对象管理相应的Java对象。当拥有MBean类后,需要将其实例化并注册到MBeanServer上。

     

    JMX的优点

    //优点就是两个字:监控!

    参考文章:https://www.zhihu.com/question/36688387/answer/1264761873

    这门技术是对Java应用程序和JVM进行监控和管理的,在企业实际开发过程中,所有的程序都是需要进行监控的,没有监控,程序就相当于是裸奔。

    在大公司中,没有监控是绝对不可能的。JMX是Java官方提供的一套用于监控Java程序和JVM运行时状态的标准API。通过JMX,我们可以监控的内容包括:

    1. 服务器中各种资源的使用情况:如CPU、内存等
    2. JVM内存使用情况
    3. JVM中的线程情况
    4. JVM中加载的类
    5. ...

    很多开源软件都是用JMX来实现性能监控的,比如大名鼎鼎的Kafka:

    Kafka 的每个监控指标都是以 JMX MBean 的形式定义的,具体来说,Kafka 使用基于 Metrics 的监控指标体系在方法调用的过程中设置埋点来统计 broke 端和 clients 端的各种监控指标,然后将采集的指标通过Metrics的JmxReporter送往JMX中。

    JConsole是用来提供运行于Java平台中的应用程序的性能与资源消耗信息的一款工具,随着JDK一同安装,只要你的电脑上安装了JDK,就肯定安装了JConsole。JMX采集到的Kafka性能数据可以通过JConsole访问到:

    通过JConsole访问JMX

    Kafka 通过JMX提供了几百个性能指标,上面这样展示方式看起来肯定是有点low。优化之后:利用JMX提供的接口可以让我们自己的程序获取到JMX中的数据,比如开源Kafka监控工具Kafka Eagle通过获取Kafka的JMX数据:

     

     

    二、3种访问JMX的方式

    参考文章:https://www.cnblogs.com/dongguacai/p/5900507.html

    2.1 通过Jconsole访问

    1、 首先定义一个MBean接口,接口的命名规范为以具体的实现类为前缀(这个规范很重要)

    package jmx;
    
    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();
    }

    2、定义一个实现类,实现上面的接口:

    1 package jmx;
     2 
     3 /*
     4  * 该类名称必须与实现的接口的前缀保持一致(即MBean前面的名称
     5  */
     6 public class Hello implements HelloMBean
     7 {
     8     private String name;
     9         
    10     private String age;
    11 
    12     public void getTelephone()
    13     {
    14         System.out.println("get Telephone");
    15     }
    16 
    17     public void helloWorld()
    18     {
    19         System.out.println("hello world");
    20     }
    21 
    22     public void helloWorld(String str)
    23     {
    24         System.out.println("helloWorld:" + str);
    25     }
    26 
    27     public String getName()
    28     {
    29         System.out.println("get name 123");
    30         return name;
    31     }
    32 
    33     public void setName(String name)
    34     {
    35         System.out.println("set name 123");
    36         this.name = name;
    37     }
    38 
    39     public String getAge()
    40     {
    41         System.out.println("get age 123");
    42         return age;
    43     }
    44 
    45     public void setAge(String age)
    46     {
    47         System.out.println("set age 123");
    48         this.age = age;
    49     }      
    53 }

    3、定义agent层:

    package jmx;
    
    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 server = ManagementFactory.getPlatformMBeanServer();
             ObjectName helloName = new ObjectName("jmxBean:name=hello");
             //create mbean and register mbean
             server.registerMBean(new Hello(), helloName);
             Thread.sleep(60*60*1000);
        }
    }

    1、其中第13行是通过工厂类获取MBeanServer,用来做MBean的容器 。

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

    3、第16行是将Hello这个类注入到MBeanServer中,注入需要创建一个ObjectName类 

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

    1、首先在自己的本地路径下:C:\Program Files (x86)\Java\jdk1.6.0_43\bin找到jconsole.exe这个小工具,双击打开:

    2、双击打开我们的本地进程:HelloAgent:

    3.在这个界面上,我们可以给程序中HelloMBean的属性赋值,也可以调用其中的方法:

    4、控制台打印如下:

     

     

    2.2 通过JMX提供的工具页访问

    这里,我们复用上面的接口和实现类,只需要改动适配层,这里需要到导入外部jar包jdmk

    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");   
             HtmlAdaptorServer adapter = new HtmlAdaptorServer();   
             server.registerMBean(adapter, adapterName);  
             adapter.start();
        }
    }

    我们访问地址:http://localhost:8082,点击name=hello:

    1、在这里创建一个AdaptorServer,这个类将决定MBean的管理界面,这里用最普通的Html型界面。AdaptorServer其实也是一个MBean。 

    2、我们可以看到这个工具页,其实与我们上一个案例中的Jconsole中的管理界面类似,都可以操作资源中的属性和方法。

    2.3 通过客户端进行远程访问JMX

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

    package jmxTest;
    
    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进行远程访问:

    2、客户端Client程序,用于与agent进行远程连接:

    package jmx;
    
    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);
        }
    }

    a、在35到41行,是对属性进行赋值和取值,这里我们不能直接调用方法,而是通过setAttribute、getAttrubute方法来进行操作,则属性的首字母要大写。

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

    下面我们来看看执行结果,先执行agent,再执行客户端:

    c、client的控制台打印结果:

    d、agent控制台打印结果:

  • 相关阅读:
    python3.7.6安装爬虫akshare
    linux执行crotab是python脚本不生效解决方案
    centos7安装smb共享目录
    搜索引擎集群安装7.8-head-ik
    npm更换阿里源
    nginx访问静态文件不下载,修改默认流下载
    jenkins通过证书ssh访问代码解决方法
    redis创建密码
    微信二次分享时缩略图及描述信息丢失
    redis安装使用
  • 原文地址:https://www.cnblogs.com/frankcui/p/10722898.html
Copyright © 2020-2023  润新知