前段时间在看btrace源码和jdk一些源码的时候,经常会看到一些jmx的相关内容。以前对jmx基本是一片空白区,花了点时间学习记录下。
过程
1. 定义MBean接口
public interface StandardServerMonitorMBean { public long getUpTime(); public void start(); }
说明:
public class StandardServerMonitor implements StandardServerMonitorMBean { public long startTime = 0; public long getUpTime() { return System.currentTimeMillis() - startTime; } @Override public void start() { startTime = System.currentTimeMillis(); } }
说明:
3. 调用测试
StandardServerMonitor serverMonitor = new StandardServerMonitor(); // 注册mbean MBeanServer mBeanServer = MBeanServerFactory.createMBeanServer(); ObjectName objectName = new ObjectName("objectName: id=serverMonitor"); mBeanServer.registerMBean(serverMonitor, objectName); // mbean调用 mBeanServer.invoke(objectName, "start", null, null); Thread.sleep(1000); Long upTime = (Long) mBeanServer.getAttribute(objectName, "UpTime"); System.out.println("uptime : " + upTime);
输出结果:
uptime : 1000
1. 实现Dynamic接口
public class DynamicServerMonitor implements DynamicMBean { private MBeanInfo mBeanInfo; private StandardServerMonitor monitor; public DynamicServerMonitor(StandardServerMonitor monitor){ this.monitor = monitor; } @Override public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { if (attribute.equals("UpTime")) { return monitor.getUpTime(); } return null; } @Override public AttributeList getAttributes(String[] attributes) { AttributeList result = new AttributeList(); for (String attr : attributes) { if (attr.equals("UpTime")) { result.add(monitor.getUpTime()); } } return result; } @Override public MBeanInfo getMBeanInfo() { if (mBeanInfo == null) { try { Class cls = StandardServerMonitor.class; // 用反射获得 "upTime" 属性的读方法 Method readMethod = cls.getMethod("getUpTime", new Class[0]); // 用反射获得构造方法 Constructor constructor = cls.getConstructor(); // 关于 "upTime" 属性的元信息:名称为 UpTime,只读属性(没有写方法)。 MBeanAttributeInfo upTimeMBeanAttributeInfo = new MBeanAttributeInfo( "UpTime", "The time span since server start", readMethod, null); // 关于构造函数的元信息 MBeanConstructorInfo mBeanConstructorInfo = new MBeanConstructorInfo("Constructor for ServerMonitor", constructor); // ServerMonitor 的元信息,为了简单起见,在这个例子里, // 没有提供 invocation 以及 listener 方面的元信息 mBeanInfo = new MBeanInfo(cls.getName(), "Monitor that controls the server", new MBeanAttributeInfo[] { upTimeMBeanAttributeInfo }, new MBeanConstructorInfo[] { mBeanConstructorInfo }, null, null); } catch (Exception e) { throw new Error(e); } } return mBeanInfo; } @Override public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException { Class[] parmeterClass = null; if (params != null) { parmeterClass = new Class[params.length]; for (int i = 0; i < params.length; i++) { parmeterClass[i] = params[i].getClass(); } } try { Method method = StandardServerMonitor.class.getMethod(actionName, parmeterClass); return method.invoke(monitor, params); } catch (Exception e) { e.printStackTrace(); } return null; } @Override public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { } @Override public AttributeList setAttributes(AttributeList attributes) { return null; } }
说明: 需要实现getAttribute/setAttribute的方法,包括invoke方法。 自己实现相应的监控方法路由
2. 调用例子
StandardServerMonitor serviceMonitor = new StandardServerMonitor(); DynamicServerMonitor dynamicServerMonitor = new DynamicServerMonitor(serviceMonitor); // 注册mbean MBeanServer mBeanServer = MBeanServerFactory.createMBeanServer(); ObjectName objectName = new ObjectName("objectName:id=dynamicServerMonitor"); mBeanServer.registerMBean(dynamicServerMonitor, objectName); // mbean调用 mBeanServer.invoke(objectName, "start", null, null); Thread.sleep(1000); Long upTime = (Long) mBeanServer.getAttribute(objectName, "UpTime"); System.out.println("uptime : " + upTime);
jvm 1.5之后默认提供了一些MBean,用于管理jvm资源,具体的MBean如下:
Object Name | MXBean | 方法描述 |
java.lang:type=ClassLoading | ClassLoadingMXBean | 包括一些类的装载信息,比如有多少类已经装载/卸载(unloaded),虚拟机类装载的 verbose 选项(即命令行中的 Java –verbose:class 选项)是否打开,还可以帮助用户打开/关闭该选项。 |
java.lang:type=Compilation | CompilationMXBean | 帮助用户了解当前的编译器和编译情况 |
java.lang:type=Memory | MemoryMXBean | 提供了整个虚拟机中内存的使用情况,包括 Java 堆(heap)和非 Java 堆所占用的内存,提供当前等待 finalize 的对象数量,它甚至可以做 gc(实际上是调用 System.gc) |
java.lang:type=OperatingSystem | OperatingSystemMXBean | 该类提供的是操作系统的简单信息,如构架名称、当前 CPU 数、最近系统负载等 |
java.lang:type=Runtime | RuntimeMXBean | 运行时信息包括当前虚拟机的名称、提供商、版本号,以及 classpath、bootclasspath 和系统参数等等 |
java.lang:type=Threading | ThreadMXBean | 可以提供的信息包括各个线程的各种状态,CPU 占用情况,以及整个系统中的线程状况。从 ThreadMXBean 可以得到某一个线程的 ThreadInfo 对象。这个对象中则包含了这个线程的所有信息 |
java.lang:type=GarbageCollector | GarbageCollectorMXBean | 仅仅提供了 GC 的次数和 GC 花费总时间的近似值 |
java.lang:type=MemoryManager | MemoryManagerMXBean | 提供了内存管理类和内存池(memory pool)的名字信息 |
java.lang:type=MemoryPool | MemoryPoolMXBean | 在 JVM 中,可能有几个内存池,因此有对应的内存池信息,因此,在工厂类中,getMemoryPoolMXBean() 得到是一个 MemoryPoolMXBean 的 list。每一个 MemoryPoolMXBean 都包含了该内存池的详细信息,如是否可用、当前已使用内存/最大使用内存值、以及设置最大内存值等等 |
说明:
1. 通过MemoryMXBean ,可以实现内存阀值控制,比如自定义一个javax.management.NotificationListener,在内存低于MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED,进行消息提醒,邮件或者短信等
2. 通过ThreadMXBean ,可以通过getLockedMonitors(),getLockedSynchronizers(),getLockInfo()获取锁信息,通过findDeadlockedThreads()检测死锁
简单的整理下jmx的相关知识,可以做为入门教程。 线上的一些监控可以通过jmx进行监控处理,做为了解还是不错的