jmx介绍及示例
2015-11-12 14:01
363 查看
最近项目中要用到JMX,好好研究了一些,发现网上也有很多没有解释清楚的,自己动手试过后总结一下。
一、什么是jmx
JMX (Java Management Extensions)是一个为应用程序,设备,系统等植入管理功能的框架。JMX是一个规范,jdk5之前有很多实现,JDK5.0则内嵌了进来,安装JDK5.0就可以开发基于JMX的代码了。简而言之,使用jmx我们可以监控jvm的运行情况,并且可扩展我们自己想要添加的监控逻辑。
二、jmx架构
Probe Level(设备层)负责资源的检测(获取信息),包含MBeans,通常也叫做Instrumentation Level。
The Agent Level 或者叫做MBean Server,是JMX的核心,连接这个Mbeans和应用程序。
Remote Management Level通过connectors和adaptors来远程操作MBeanServer, Applications可以是大家比较熟悉的控制台,例如JConsole。
三、MBean(Managed beans)
一个MBean是一个被管理的java对象,有点类似于Javabean,一个设备、一个应用或者任何资源都可以被表示为MBean。MBean会暴露一个对外接口,通过这个接口可以读取或者写入一些对象中的属性,操作对象的方法。JMX提供了四种MBean,分别是标准MBean、动态MBean、模型MBean和开发MBean。
(1)标准MBean
Standard Mbean是最简单的MBean,他能管理的资源必须定义在接口中,然后MBean必须实现这个接口,命名必须遵守一定的规范。
示例:
1、编写MBean的接口:ControllerMBean.java
2、编写MBean接口的实现类:Controller.java
3、创建一个Agent类:ControllerTestJMX.java
添加后可以打开JConsole查看:
(2)动态MBean
动态MBean的最大的特点是可以在运行期暴露自己的管理接口,因此具有更好的灵活性。它的实现是通过实现一个特定的接口DynamicMBean。
当DynamicMBean在JMX agent中注册后,DynamicMBean其实就和StandardMBean 是一样的,外界将首先通过getMBeanInfo获得一个管理接口,其中包含attributes 和 operations 名称,然后才将调用DynamicMBean的getters, setters 和invoke方法。 适合管理那些已经存在的资源和代码。
1、 TestDynamicMBean.java:实现了DynamicMBean接口
2、Agent类:ControllerTestJMX.java
打开jconsole后进入MBean中会看到刚才注册的myDynamicMBean,点开节点,到操作,点击addAttribute方法(添加属性),提示成功添加属性。再次新打开一个jconsole窗口,可看到新添加的属性value。
四、监控
上面我们已经学习到如何开发jmx用例,如何获得监控的数据是我们的重点,下面通过监控tomcat来描述,tomcat实现了jmx,并且已注册了多种MBean供开发人员监控其性能。
下面实现对tomcat的大部分参数的监控:
1、首先配置tomcat,在catalina.sh中配置JAVA_OPTS
JAVA_OPTS=”-Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=10.25.4.129
-Dcom.sun.management.jmxremote.port=8050 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false”
启动tomcat。其中8050就是jmx远程连接端口(可以修改为其它)
2、编写测试类
关于ObjectName 可以正则匹配,这个一直没有实现,希望有成功经验的可以不吝赐教。
一、什么是jmx
JMX (Java Management Extensions)是一个为应用程序,设备,系统等植入管理功能的框架。JMX是一个规范,jdk5之前有很多实现,JDK5.0则内嵌了进来,安装JDK5.0就可以开发基于JMX的代码了。简而言之,使用jmx我们可以监控jvm的运行情况,并且可扩展我们自己想要添加的监控逻辑。
二、jmx架构
Probe Level(设备层)负责资源的检测(获取信息),包含MBeans,通常也叫做Instrumentation Level。
The Agent Level 或者叫做MBean Server,是JMX的核心,连接这个Mbeans和应用程序。
Remote Management Level通过connectors和adaptors来远程操作MBeanServer, Applications可以是大家比较熟悉的控制台,例如JConsole。
三、MBean(Managed beans)
一个MBean是一个被管理的java对象,有点类似于Javabean,一个设备、一个应用或者任何资源都可以被表示为MBean。MBean会暴露一个对外接口,通过这个接口可以读取或者写入一些对象中的属性,操作对象的方法。JMX提供了四种MBean,分别是标准MBean、动态MBean、模型MBean和开发MBean。
(1)标准MBean
Standard Mbean是最简单的MBean,他能管理的资源必须定义在接口中,然后MBean必须实现这个接口,命名必须遵守一定的规范。
示例:
1、编写MBean的接口:ControllerMBean.java
public interface ControllerMBean { /*需遵从的规范: 1、名字必须以MBean结尾 2、必须有相关属性的getXXX()和setXXX()方法名*/ public void setName(String name); public String getName(); public String status(); public void start(); public void stop(); }
2、编写MBean接口的实现类:Controller.java
public class Controller implements ControllerMBean { /*需遵从的规范: 1、名字必须和接口中 "MBean" 的前缀相同(不知道是不是新版本的规定,很多都没有说明,期初没有相同调试程序一直不过) 2、实现接口中的方法*/ private String name; @Override public void setName(String name) { // TODO Auto-generated method stub this.name=name; } @Override public String getName() { // TODO Auto-generated method stub return this.name; } @Override public String status() { // TODO Auto-generated method stub System.out.println("this is a Controller MBean,name is " + this.name); return "this is a Controller MBean,name is " + this.name; } @Override public void start() { // TODO Auto-generated method stub } @Override public void stop() { // TODO Auto-generated method stub }
3、创建一个Agent类:ControllerTestJMX.java
public class ControllerTestJMX { public static void main(String[] args) throws MalformedObjectNameException, NullPointerException, InstanceAlreadyExistsException, NotCompliantMBeanException, InstanceNotFoundException, ReflectionException, MBeanException { // MBeanServer mbs = MBeanServerFactory.createMBeanServer();//不能在jconsole中使用 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();//可在jconsole中使用 //创建标准MBean Controller controller = new Controller(); ObjectName controllerName = new ObjectName("myBean:name=controller,type=test"); //将标准MBean注册到MBeanServer中 mbs.registerMBean(controller, controllerName); mbs.invoke(controllerName, "status", null, null); try { Thread.sleep(1000000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
添加后可以打开JConsole查看:
(2)动态MBean
动态MBean的最大的特点是可以在运行期暴露自己的管理接口,因此具有更好的灵活性。它的实现是通过实现一个特定的接口DynamicMBean。
当DynamicMBean在JMX agent中注册后,DynamicMBean其实就和StandardMBean 是一样的,外界将首先通过getMBeanInfo获得一个管理接口,其中包含attributes 和 operations 名称,然后才将调用DynamicMBean的getters, setters 和invoke方法。 适合管理那些已经存在的资源和代码。
1、 TestDynamicMBean.java:实现了DynamicMBean接口
public class TestDynamicMBean implements DynamicMBean { private String mc = "myDynamicMBean"; private MBeanAttributeInfo[] dAttributes; private MBeanOperationInfo[] opers=new MBeanOperationInfo[3]; private MBeanConstructorInfo[] constructors = new MBeanConstructorInfo[1]; MBeanInfo info; private String value="hello"; public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getMc() { return mc; } public void setMc(String name) { this.mc = name; } public void printName() { System.out.println(mc); } public TestDynamicMBean() { init(); System.out.println("构造函数"); } public void init() { Constructor[] thisconstructors = this.getClass().getConstructors(); constructors[0] = new MBeanConstructorInfo("TestDynamicMBean(): Constructs a TestDynamicMBean object", thisconstructors[0]); //可用的方法是在 MBeanInfo 接口中指定的 dAttributes = new MBeanAttributeInfo[] { new MBeanAttributeInfo( "mc" , "String" , "缓存名称" , true , true , false )}; /* MBeanOperationInfo opers[] = { new MBeanOperationInfo( "printName" , "print" , null , "void" ,MBeanOperationInfo.ACTION), new MBeanOperationInfo( "setMc" , "setMc" , null , "void" ,MBeanOperationInfo.ACTION), new MBeanOperationInfo( "addAttribute" , "addAttribute" , null , "void" ,MBeanOperationInfo.ACTION) };*/ opers[0]= new MBeanOperationInfo( "printName" , "print" , null , "void" ,MBeanOperationInfo.ACTION); opers[1]= new MBeanOperationInfo( "setMc" , "setMc" , null , "void" ,MBeanOperationInfo.ACTION); opers[2]= new MBeanOperationInfo( "addAttribute" , "addAttribute" , null , "void" ,MBeanOperationInfo.ACTION); info = new MBeanInfo( this .getClass().getName(), "TestDynamic" , dAttributes, null , opers, null ); } /*动态添加属性 * */ public void addAttribute() { System.out.println("开始调用addAttribute"); dAttributes=new MBeanAttributeInfo[2]; dAttributes[0]=new MBeanAttributeInfo( "name" , "String" , "缓存name" , true , true , false ); dAttributes[1]=new MBeanAttributeInfo( "value" , "String" , "缓存value" , true , true , false ); System.out.println("已增加value属性"); info = new MBeanInfo( this .getClass().getName(), "TestDynamic" , dAttributes, null , opers, null ); } @Override public Object getAttribute(String arg0) throws AttributeNotFoundException, MBeanException, ReflectionException { // TODO Auto-generated method stub System.out.println("getAttribute"); if (arg0== null ){ throw new AttributeNotFoundException(); } if ( "name" .equalsIgnoreCase(arg0)){ return getMc(); } if ( "value" .equalsIgnoreCase(arg0)){ return getValue(); } throw new AttributeNotFoundException(); } @Override public AttributeList getAttributes(String[] arg0) { // TODO Auto-generated method stub return null; } @Override public MBeanInfo getMBeanInfo() { // TODO Auto-generated method stub System.out.println("调用getMBeanInfo方法"); System.out.println(dAttributes.length); return info; } @Override public Object invoke(String arg0, Object[] arg1, String[] arg2) throws MBeanException, ReflectionException { // TODO Auto-generated method stub if ( "printName" .equals(arg0)){ printName(); } if ( "addAttribute" .equals(arg0)){ addAttribute(); } return null ; } @Override public void setAttribute(Attribute arg0) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { // TODO Auto-generated method stub System.out.println("setAttribute"); String name = arg0.getName(); Object value = arg0.getValue(); if ( "name" .equalsIgnoreCase(name)){ this .setMc(String.valueOf(value)); return ; } if ( "value" .equalsIgnoreCase(name)){ this .setValue(String.valueOf(value)); return ; } throw new AttributeNotFoundException(); } @Override public AttributeList setAttributes(AttributeList arg0) { // TODO Auto-generated method stub return null; }
2、Agent类:ControllerTestJMX.java
public class ControllerTestJMX { public static void main(String[] args) throws MalformedObjectNameException, NullPointerException, InstanceAlreadyExistsException, NotCompliantMBeanException, InstanceNotFoundException, ReflectionException, MBeanException { // MBeanServer mbs = MBeanServerFactory.createMBeanServer();//不能在jconsole中使用 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();//可在jconsole中使用 //创建动态MBean TestDynamicMBean dynamicMBean = new TestDynamicMBean(); ObjectName dynamicMBeanName = new ObjectName("myDynamicMBean:name=TestDynamicMBean,type=testDynamic"); //将动态MBean注册到MBeanServer中 mbs.registerMBean(dynamicMBean, dynamicMBeanName); // mbs.invoke(dynamicMBeanName, "status", null, null); try { Thread.sleep(1000000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
打开jconsole后进入MBean中会看到刚才注册的myDynamicMBean,点开节点,到操作,点击addAttribute方法(添加属性),提示成功添加属性。再次新打开一个jconsole窗口,可看到新添加的属性value。
四、监控
上面我们已经学习到如何开发jmx用例,如何获得监控的数据是我们的重点,下面通过监控tomcat来描述,tomcat实现了jmx,并且已注册了多种MBean供开发人员监控其性能。
下面实现对tomcat的大部分参数的监控:
1、首先配置tomcat,在catalina.sh中配置JAVA_OPTS
JAVA_OPTS=”-Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=10.25.4.129
-Dcom.sun.management.jmxremote.port=8050 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false”
启动tomcat。其中8050就是jmx远程连接端口(可以修改为其它)
2、编写测试类
public class JmxTest { public static void main(String[] args){ try { String jmxURL = "service:jmx:rmi:///jndi/rmi://10.25.4.129:8050/jmxrmi";//tomcat jmx url JMXServiceURL serviceURL = new JMXServiceURL(jmxURL); /*下面这三行代码提供注册所需的用户名,密码,tomcat中参数-Dcom.sun.management.jmxremote.authenticate="false" 配为false,就不需要了*/ Map map = new HashMap(); String[] credentials = new String[] { "monitorRole", "QED" }; map.put("jmx.remote.credentials", credentials); JMXConnector connector = JMXConnectorFactory.connect(serviceURL, map); MBeanServerConnection mbsc = connector.getMBeanServerConnection(); //端口最好是动态取得 ObjectName threadObjName = new ObjectName("Catalina:name=\"http-bio-9666\",type=ThreadPool"); /*其中Catalina:name="http-bio-9666",type=ThreadPool是tomcat中已有的MBean*/ MBeanInfo mbInfo = mbsc.getMBeanInfo(threadObjName); String attrName = "currentThreadCount";//tomcat的线程数对应的属性值 MBeanAttributeInfo[] mbAttributes = mbInfo.getAttributes(); System.out.println("currentThreadCount:" + mbsc.getAttribute(threadObjName, attrName)); //heap for (int j = 0; j < mbsc.getDomains().length; j++) { System.out.println("###########" + mbsc.getDomains()[j]); } Set MBeanset = mbsc.queryMBeans(null, null); System.out.println("MBeanset.size() : " + MBeanset.size()); Iterator MBeansetIterator = MBeanset.iterator(); while (MBeansetIterator.hasNext()) { ObjectInstance objectInstance = (ObjectInstance) MBeansetIterator.next(); ObjectName objectName = objectInstance.getObjectName(); String canonicalName = objectName.getCanonicalName(); System.out.println("canonicalName : " + canonicalName); if (canonicalName.equals("Catalina:host=localhost,type=Cluster")) { // Get details of cluster MBeans System.out.println("Cluster MBeans Details:"); System.out.println("========================================="); //getMBeansDetails(canonicalName); String canonicalKeyPropList = objectName.getCanonicalKeyPropertyListString(); } } //------------------------- system ---------------------- ObjectName runtimeObjName = new ObjectName("java.lang:type=Runtime"); System.out.println("厂商:" + (String) mbsc.getAttribute(runtimeObjName, "VmVendor")); System.out.println("程序:" + (String) mbsc.getAttribute(runtimeObjName, "VmName")); System.out.println("版本:" + (String) mbsc.getAttribute(runtimeObjName, "VmVersion")); Date starttime = new Date((Long) mbsc.getAttribute(runtimeObjName, "StartTime")); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("启动时间:" + df.format(starttime)); Long timespan = (Long) mbsc.getAttribute(runtimeObjName, "Uptime"); System.out.println("连续工作时间:" + JmxTest.formatTimeSpan(timespan)); //------------------------ JVM ------------------------- //堆使用率 ObjectName heapObjName = new ObjectName("java.lang:type=Memory"); MemoryUsage heapMemoryUsage = MemoryUsage.from((CompositeDataSupport) mbsc.getAttribute(heapObjName, "HeapMemoryUsage")); long maxMemory = heapMemoryUsage.getMax();//堆最大 long commitMemory = heapMemoryUsage.getCommitted();//堆当前分配 long usedMemory = heapMemoryUsage.getUsed(); System.out.println("heap:" + (double) usedMemory * 100 / commitMemory + "%");//堆使用率 MemoryUsage nonheapMemoryUsage = MemoryUsage.from((CompositeDataSupport) mbsc.getAttribute(heapObjName, "NonHeapMemoryUsage")); long noncommitMemory = nonheapMemoryUsage.getCommitted(); long nonusedMemory = heapMemoryUsage.getUsed(); System.out.println("nonheap:" + (double) nonusedMemory * 100 / noncommitMemory + "%"); ObjectName permObjName = new ObjectName("java.lang:type=MemoryPool,name=Perm Gen"); MemoryUsage permGenUsage = MemoryUsage.from((CompositeDataSupport) mbsc.getAttribute(permObjName, "Usage")); long committed = permGenUsage.getCommitted();//持久堆大小 long used = heapMemoryUsage.getUsed();// System.out.println("perm gen:" + (double) used * 100 / committed + "%");//持久堆使用率 //-------------------- Session --------------- ObjectName managerObjName = new ObjectName("Catalina:type=Manager,*"); Set<ObjectName> s = mbsc.queryNames(managerObjName, null); for (ObjectName obj : s) { System.out.println("应用名:" + obj.getKeyProperty("path")); ObjectName objname = new ObjectName(obj.getCanonicalName()); System.out.println("最大会话数:" + mbsc.getAttribute(objname, "maxActiveSessions")); System.out.println("会话数:" + mbsc.getAttribute(objname, "activeSessions")); System.out.println("活动会话数:" + mbsc.getAttribute(objname, "sessionCounter")); } //----------------- Thread Pool ---------------- ObjectName threadpoolObjName = new ObjectName("Catalina:type=ThreadPool,*"); Set<ObjectName> s2 = mbsc.queryNames(threadpoolObjName, null); for (ObjectName obj : s2) { System.out.println("端口名:" + obj.getKeyProperty("name")); ObjectName objname = new ObjectName(obj.getCanonicalName()); System.out.println("最大线程数:" + mbsc.getAttribute(objname, "maxThreads")); System.out.println("当前线程数:" + mbsc.getAttribute(objname, "currentThreadCount")); System.out.println("繁忙线程数:" + mbsc.getAttribute(objname, "currentThreadsBusy")); } } catch (Exception e) { e.printStackTrace(); } } public static String formatTimeSpan(long span) { long minseconds = span % 1000; span = span / 1000; long seconds = span % 60; span = span / 60; long mins = span % 60; span = span / 60; long hours = span % 24; span = span / 24; long days = span; return (new Formatter()).format("%1$d天 %2$02d:%3$02d:%4$02d.%5$03d", days, hours, mins, seconds, minseconds) .toString(); } }
关于ObjectName 可以正则匹配,这个一直没有实现,希望有成功经验的可以不吝赐教。
相关文章推荐
- JMX和MBean以及pojo-mbean学习
- 通过JMX监控tomcat在Linux下的设置
- JMX学习之MBean
- Felix?OSGi? -初步了解
- ActiveMQ (2)
- J2EE运行环境性能优化艺术之二
- J2EE开源消息中间件大比拼
- Java SE 6 新特性: JMX 与系统管理
- cluster
- 继续进阶的学习自律
- 了解 Java SE 6 新特性系列
- 关于The MBean class could not be loaded by the default loader repository的解决方法
- JConsole的使用手册(转载)
- jmx在tomcat中的应用
- 使用AdminClient 连接Websphere 7
- 大家是不是都不看这个?
- JBOSS5.0 Beta4 配置详解
- what's QMF?
- 再论模式
- Spring JMX demo 例子