一、为什么使用JMX,解决那些问题

举一个应用实例:在一个系统中常常会有一些配置信息,比如服务的IP地址,端口号什么的,那么如何来写这些代码呢?
  1. 写死在程序里,到要改变时就去改程序,然后再编译发布;
  2. 把这些信息写在一个配置文件里(JAVA一般都是*.properties文件),到要改变时只要改配置文件,但还是重新启动系统,以便读取配置文件里的新值;
  3. 写一个段代码,把配置值缓存起来,系统在读值的时候,先看看配置文件有没有更动。如有更改则重读一遍,否则从缓存里读取值
  4. 用JMX!把配置属性集中在一个类,然后写一个叫MBean的东东,再配置一下就轻松搞定了。而且JMX自动提供了一个WEB页面来给你来改变这些配置信息。

JMX是一种JAVA的正式规范,它主要目的是让程序有被管理的功能。试想你开发了一个软件(如WEB网站),它是在24小时不间断运行的,那么你可能会想要“监控”这个软件的运行情况,比如收到了多少数据,有多少人登录等等。或者你又想“配置”这个软件,比如现在访问人数比较多,你想把数据连接池设置得大一些。

二、JMX使用

JMX 全称是 Java Management Extensions, Java5.0开始引入,提供连接、监控和管理远程JVM的方式。

MBean

一个MBean是一个被管理的Java对象,有点类似于JavaBean,一个设备、一个应用或者任何资源都可以被表示为MBean,MBean会暴露一个接口对外,这个接口可以读取或者写入一些对象中的属性,通常一个MBean需要定义一个接口,以MBean结尾,例如:DataSourceMBean, 格式为XXXMBean,这个是规范,必须得遵守。

MBeanServer

MBean的容器,提供远程访问、命名空间管理和安全服务。

JMX 指定了在 MBeanServer 和 JMX 客户之间通信所使用的协议,协议可以在各种传输机制上运行。可以使用针对本地连接的内置传输,及通过 RMI、socket 或 SSL 的远程传输(可以通过 JMX Connector API 创建新的传输)。

示例:

  1. public interface HelloMBean {
  2. public String getName();
  3. public void setName(String name);
  4. public void printHello();
  5. public void printHello(String whoName);
  6. }
  1. public class Hello implements HelloMBean {
  2.  
  3. private String name = "loull";
  4.  
  5. @Override
  6. public String getName() {
  7. return name;
  8. }
  9.  
  10. @Override
  11. public void setName(String name) {
  12. this.name = name;
  13. }
  14.  
  15. @Override
  16. public void printHello() {
  17. System.out.println("Hello, " + name);
  18. }
  19.  
  20. @Override
  21. public void printHello(String whoName) {
  22. System.out.println("Hello, " + whoName);
  23. }
  24. }

本地agent

  1. import javax.management.InstanceAlreadyExistsException;
  2. import javax.management.MBeanRegistrationException;
  3. import javax.management.MBeanServer;
  4. import javax.management.MalformedObjectNameException;
  5. import javax.management.NotCompliantMBeanException;
  6. import javax.management.ObjectName;
  7.  
  8. public class HelloAgent {
  9.  
  10. private static final String MBEAN_NAME = "com.jmxtest:type=HelloMBean";
  11.  
  12. public static void main(String[] args) throws MalformedObjectNameException,
  13. InstanceAlreadyExistsException,
  14. MBeanRegistrationException, NotCompliantMBeanException,
  15. InterruptedException {
  16. // MBeanServer server = MBeanServerFactory.createMBeanServer();
  17. MBeanServer server = ManagementFactory.getPlatformMBeanServer();
  18.  
  19. ObjectName helloName = new ObjectName(MBEAN_NAME);
  20.  
  21. Hello hello = new Hello();
  22.  
  23. server.registerMBean(hello, helloName);
  24.  
  25. System.out.println("start...");
  26. Thread.currentThread().join();
  27. }
  28.  
  29. }

这样就可以了。然后我们就可以使用jconsole进行监控和管理了。需要注意的是这里需要使用getPlatformMBeanServer才能够被jconsole监控到,创建新的MBeanServer是监控不到的。原因是JConsole通过Attach API动态attach到已经运行的目标JVM,然后命令其动态的load了JDK_HOME/lib/management-agent.jar这个agent包,这个agent包的agentmain方法会对PlatformMBeanServer进行RMI注册和监听。

html agent

  1. import javax.management.InstanceAlreadyExistsException;
  2. import javax.management.MBeanRegistrationException;
  3. import javax.management.MBeanServer;
  4. import javax.management.MBeanServerFactory;
  5. import javax.management.MalformedObjectNameException;
  6. import javax.management.NotCompliantMBeanException;
  7. import javax.management.ObjectName;
  8.  
  9. import com.sun.jdmk.comm.HtmlAdaptorServer;
  10.  
  11. public class HelloHtmlAgent {
  12.  
  13. private static final String MBEAN_NAME = "com.alipay.jmxtest:type=HelloMBean";
  14.  
  15. public static void main(String[] args) throws MalformedObjectNameException,
  16. InstanceAlreadyExistsException,
  17. MBeanRegistrationException, NotCompliantMBeanException {
  18. //创建MBeanServer
  19. MBeanServer server = MBeanServerFactory.createMBeanServer();
  20. //创建MBean ObjectName
  21. ObjectName helloName = new ObjectName("MBeanTest:name=HelloWorld");
  22. //注册MBean
  23. Hello hello = new Hello();
  24. server.registerMBean(hello, helloName);
  25.  
  26. ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8082");
  27. HtmlAdaptorServer adapter = new HtmlAdaptorServer();
  28. server.registerMBean(adapter, adapterName);
  29.  
  30. adapter.start();
  31. System.out.println("start.....");
  32. }
  33.  
  34. } 

运行HelloAgent,然后打开网页:http://localhost:8082/。单击“name=HelloWorld”链接进入。

说明:

先创建了一个MBeanServer,用来做MBean的容器      将Hello这个类注入到MBeanServer中,注入需要创建一个ObjectName类      创建一个AdaptorServer,这个类将决定MBean的管理界面,这里用最普通的Html型界面。AdaptorServer其实也是一个MBean。      "MBeanTest:name=HelloWorld"的名字是有一定规则的,格式:“域名:name=MBean名称”,域名和MBean名称都可以任意取。

在实际系统中我们可以把name变成决定数库链接池的变量,这样我就可以对系统的运行参数进行实现的监控和配置(管理)。

三、JMX 提供的虚拟机检测API

检测虚拟机当前的状态总是 Java 开放人员所关心的,从 Java SE 5 之后,java.lang.management包里面包括了许多MXBean的接口类和 LockInfo、MemoryUsage、MonitorInfo 和 ThreadInfo 等类。从名字可以看出,该包提供了虚拟机内存分配、垃圾收集(GC)情况、操作系统层、线程调度和共享锁,甚至编译情况的检测机制。

JVM在启动的时候会默认将这些内建的MBean注册到PlatfromMBeanServer。这样一来,Java 的开发人员就可以很简单地为自己做一些轻量级的系统检测,来确定当前程序的各种状态,以便随时调整。jconsole的MBeans中就能够看到这些系统MXBeans。

具体有如下这些MXBean Package java.lang.management:

  • ClassLoadingMXBean: ClassLoadMXBean 包括一些类的装载信息,比如有多少类已经装载/卸载(unloaded),虚拟机类装载的 verbose 选项(即命令行中的 Java – verbose:class 选项)是否打开,还可以帮助用户打开 / 关闭该选项。
  • CompilationMXBean: CompilationMXBean 帮助用户了解当前的编译器和编译情况,该 mxbean 提供的信息不多。
  • GarbageCollectorMXBean: 相对于开放人员对 GC 的关注程度来说,该 mxbean 提供的信息十分有限,仅仅提供了 GC 的次数和 GC 花费总时间的近似值。但是这个包中还提供了三个的内存管理检测类:MemoryManagerMXBean,MemoryMXBean 和 MemoryPoolMXBean。
  • MemoryManagerMXBean: 这个类相对简单,提供了内存管理类和内存池(memory pool)的名字信息。
  • MemoryMXBean: 这个类提供了整个虚拟机中内存的使用情况,包括 Java 堆(heap)和非 Java 堆所占用的内存,提供当前等待 finalize 的对象数量,它甚至可以做 gc(实际上是调用 System.gc)。
  • MemoryPoolMXBean: 该信息提供了大量的信息。在 JVM 中,可能有几个内存池,因此有对应的内存池信息,因此,在工厂类中,getMemoryPoolMXBean() 得到是一个 MemoryPoolMXBean 的 list。每一个 MemoryPoolMXBean 都包含了该内存池的详细信息,如是否可用、当前已使用内存 / 最大使用内存值、以及设置最大内存值等等。
  • OperatingSystemMXBean: 该类提供的是操作系统的简单信息,如构架名称、当前 CPU 数、最近系统负载等。
  • RuntimeMXBean: 运行时信息包括当前虚拟机的名称、提供商、版本号,以及 classpath、bootclasspath 和系统参数等等。
  • ThreadMXBean: 在 Java 这个多线程的系统中,对线程的监控是相当重要的。ThreadMXBean 就是起到这个作用。ThreadMXBean 可以提供的信息包括各个线程的各种状态,CPU 占用情况,以及整个系统中的线程状况。从 ThreadMXBean 可以得到某一个线程的 ThreadInfo 对象。这个对象中则包含了这个线程的所有信息。

如果我们要想获得这些信息,只需要简单的通过java.lang.management.ManagementFactory这个工厂类(单例)来获得相应的的MXBean,然后就可以通过这个MBean获取其监控的数据了:

  1. RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
  2. // Get the standard attribute "VmVendor"
  3. String vendor = mxbean.getVmVendor();
  4.  
  5. // Or by calling the getPlatformMXBean or getPlatformMXBeans method:
  6. RuntimeMXBean mxbean = ManagementFactory.getPlatformMXBean(RuntimeMXBean.class);
  7. // Get the standard attribute "VmVendor"
  8. String vendor = mxbean.getVmVendor();

或者Construct an MXBean proxy instance that forwards the method calls to a given MBeanServer:

  1. MBeanServerConnection mbs;
  2.  
  3. // Connect to a running JVM (or itself) and get MBeanServerConnection
  4. // that has the JVM MBeans registered in it
  5. ...
  6.  
  7. // Get a MBean proxy for RuntimeMXBean interface
  8. RuntimeMXBean proxy = ManagementFactory.getPlatformMXBean(mbs, RuntimeMXBean.class);
  9. // Get standard attribute "VmVendor"
  10. String vendor = proxy.getVmVendor(); 

Tomcat有个Tomcat Manager工程就是通过JMXProxyServlet暴露JMX监控项的。它的实现其实非常简单,就是根据用户指定的MBeanName和Attribute,在platformMBeanServer中访问该MBean的属性而已。

核心代码就是这几个函数

  1. public void getAttribute(PrintWriter writer, String onameStr, String att) {
  2. try {
  3. ObjectName oname = new ObjectName(onameStr);
  4. Object value = mBeanServer.getAttribute(oname, att);
  5. writer.println("OK - Attribute get '" + onameStr + "' - " + att
  6. + "= " + escape(value.toString()));
  7. } catch (Exception ex) {
  8. writer.println("Error - " + ex.toString());
  9. }
  10. }
  11.  
  12. public void setAttribute( PrintWriter writer,
  13. String onameStr, String att, String val )
  14. {
  15. try {
  16. ObjectName oname=new ObjectName( onameStr );
  17. String type=registry.getType(oname, att);
  18. Object valueObj=registry.convertValue(type, val );
  19. mBeanServer.setAttribute( oname, new Attribute(att, valueObj));
  20. writer.println("OK - Attribute set");
  21. } catch( Exception ex ) {
  22. writer.println("Error - " + ex.toString());
  23. }
  24. }
  25.  
  26. public void listBeans( PrintWriter writer, String qry )
  27. {
  28.  
  29. Set names = null;
  30. try {
  31. names=mBeanServer.queryNames(new ObjectName(qry), null);
  32. writer.println("OK - Number of results: " + names.size());
  33. writer.println();
  34. } catch (Exception e) {
  35. writer.println("Error - " + e.toString());
  36. return;
  37. }
  38.  
  39. Iterator it=names.iterator();
  40. while( it.hasNext()) {
  41. ObjectName oname=(ObjectName)it.next();
  42. writer.println( "Name: " + oname.toString());
  43.  
  44. try {
  45. MBeanInfo minfo=mBeanServer.getMBeanInfo(oname);
  46. // can't be null - I thinl
  47. String code=minfo.getClassName();
  48. if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) {
  49. code=(String)mBeanServer.getAttribute(oname, "modelerType");
  50. }
  51. writer.println("modelerType: " + code);
  52.  
  53. MBeanAttributeInfo attrs[]=minfo.getAttributes();
  54. Object value=null;
  55.  
  56. for( int i=0; i< attrs.length; i++ ) {
  57. if( ! attrs[i].isReadable() ) continue;
  58. if( ! isSupported( attrs[i].getType() )) continue;
  59. String attName=attrs[i].getName();
  60. if( attName.indexOf( "=") >=0 ||
  61. attName.indexOf( ":") >=0 ||
  62. attName.indexOf( " ") >=0 ) {
  63. continue;
  64. }
  65.  
  66. try {
  67. value=mBeanServer.getAttribute(oname, attName);
  68. } catch( Throwable t) {
  69. log("Error getting attribute " + oname +
  70. " " + attName + " " + t.toString());
  71. continue;
  72. }
  73. if( value==null ) continue;
  74. if( "modelerType".equals( attName)) continue;
  75. String valueString=value.toString();
  76. writer.println( attName + ": " + escape(valueString));
  77. }
  78. } catch (Exception e) {
  79. // Ignore
  80. }
  81. writer.println();
  82. }
  83. }

JMXProxyServlet的作用是将MBean数据以HTTP方式而不是RMI方式暴露出去。对于页面展示也好,或者穿越防火墙来说都是比较友好的。

JMX的更多相关文章

  1. ActiveMQ笔记(5):JMX监控

    系统上线运行后,及时监控报警是很必要的手段,对于ActiveMQ而言,主要监控的指标有:MQ本身的健康状况.每个队列的生产者数量.消费者数量.队列的当前消息数等. ActiveMQ支持JMX监控,使用 ...

  2. Java_jvisualvm使用JMX连接远程机器(实践)

    https://my.oschina.net/heroShane/blog/196227 一.启动普通的jar程序 1.执行foo.jar启动命令 java -Dcom.sun.management. ...

  3. Tomcat调优及JMX监控

    Tomcat调优及JMX监控 实验背景 ====================================================== 系统版本:CentOS release 6.5 ( ...

  4. docker-compose启动的tomcat无法远程连接jmx

    最近想学习下java GC优化,就用了一下VisualVM,在远程服务器启动了一个非docker的tomcat,很顺利的就连接了,但是用docker-compose启动的服务却 怎么也连不上,一定是d ...

  5. 开启JMX功能,使JVisvualVM能够连接JVM

    -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.manageme ...

  6. jmx配置

    # ----- Execute The Requested Command ----------------------------------------- # ----- JMX Config S ...

  7. 压测如何观测jvm,就是使用jmx来实现jvm监控

    jps.jstack.jmap.jhat.jstat.hprof 基于jmx可以开发web版本,方便压测的时候观测jvm以及线程的信息 ================================ ...

  8. jmx server 和jmx client

    启动jmx server 和jmx client,通过jconsole进入jmx server 然后通过其中远程进程,进入jmx client: 发现,两者可用的tab页不同, MBean的数量类型也 ...

  9. jmx : ClientCommunicatorAdmin Checker-run

    今天遇到一个问题: 执行bat,关闭jmx的时候,由于程序关闭之后又去连接了一次,cmd窗口报错,类似: 2013-7-11 15:58:05 ClientCommunicatorAdmin rest ...

随机推荐

  1. DataSet、DataTable、Json、List 等各种数据的相互转化

      1.根据Dataset生成json格式的字符串,不管Dataset里面有多少个表都可以一一生成对应的json字符串,并一次性返回 private string dsToJson(DataSet d ...

  2. 2012 Multi-University #8

    DP+单调队列优化 E One hundred layer 题意:n*m的矩形,从第一层x位置往下走,每一层都可以往左或往右移动最多k步再往下走,问走到n层时所走路径的最大值. 分析:定义,,注意到m ...

  3. python 自带的ide 不能保存文件

    初学python 用shell写的代码结果不能保存,经查询,原因有人说是因为文件里有中文, import random secret =random.randint(1,100) guess=0 tr ...

  4. JDBC连接数据库(数据源的方式)

    在tomcat安装目录下的context.xml文件中配置DataSource <Resource name="jdbc/news"(JNDI的名字,news是数据库的实例名 ...

  5. BFC给我的帮助以及对hasLayout的认识

    布局的时候经常想让一个或几个元素并并排的放在一起,有时给其中的一个浮动,元素是在一行了,可还是都左边重叠了,总是这样那样改来改去,小白的我也是醉了! 今天偶然间看到了了BFC这个东东,虽然现在还是不是 ...

  6. js模块开发(一)

    现在嵌入页面里面的javascript代码越来越复杂,于是可能依赖也越来越严重,使用别人开发的js也越来越多,于是在理想情况下,我们只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块. 于是j ...

  7. Java_动态编译总结

    不多说直接上代码: 动态编译的主类: package com.lkb.autoCode.util; import com.lkb.autoCode.constant.AutoCodeConstant; ...

  8. java分享第十一天(接口测试)

     HTTP协议的接口测试中,使用到最多的就是GET请求与POST请求,其中POST请求有FORM参数提交请求与RAW请求( post请求时有一个选项是form-data,或者raw,使用raw可以请求 ...

  9. 推流和拉流的概念以及RTMP和HLS协议

    推流为将直播内容推送至服务器的过程:拉流为服务器已有直播内容,用指定地址进行拉取的过程. rtmp rtmp是Real Time Messaging Protocol(实时消息传输协议)的首字母缩写. ...

  10. idea intellij 混淆anroid代码

    idea intellij 混淆anroid代码 在project.properties中加入 target=android-14proguard.config=proguard.cfg 点击 Bui ...