JMX是Java Management Extensions 的简写,即Java管理扩展.
通过JMX,我们可以监控的内容包括:
1、服务器中各种资源的使用情况:如CPU、内存等
2、JVM内存使用情况
3、JVM中的线程情况
4、JVM中加载的类
JMX技术可以被分为3层,如下:
* 监测(Instrumentation)
* JMX代理
* 远程管理
监控层的作用就是使用MBean来监控我们关心的性能指标。因为通常关注的性能指标比较多,通常情况下,在监控层我们会有多个MBean,每个MBean监控一类信息。
JMX代理相当于一个容器,所有的MBean都注册到这个容器中。这个容器可以接受外部的请求,返回MBean的监控信息。当我们想从远程获取某个MBean的检测信息,我们就给这个容器发送一个请求,由这个容器将这个MBean的检测信息返回给我们。JMX代理的核心组件是MBean server,它是一个被管理对象的服务器,MBeans在其中注册。一个JMX代理还包括一组用于管理MBeans的服务和至少一个通信适配器(adaptor)或连接器(connector) 以供管理程序访问。
使用一个远程客户端连接MBean Server来获取MBean的监控信息。
JMX规范定义了5种MBean:
1. 标准MBeans
2. 动态MBeans
3. Open MBeans
4. Model MBeans
5. MXBeans
但是对于我们日常需要监控的数据,我们只需要编码方式比较简单的标准MBeans即可,这种方式返回的都是基本的数据类型。
下面讲解标准MBean的编写方式和规范
要有一个叫xxxMBean的接口,然后继承这个MBean接口的类名必须是xxx类,否则无法注册到jmx代理中。
实现类
public class Test implements TestMBean {
private String name = "你好啊";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String printHello() {
String name = "你好!";
return name;
}
@Override
public String printTestParams(String param) {
return param;
}
}
接口
public interface TestMBean {
public String printHello();
public String printTestParams(String param);
}
上述代码中的第二种方法可以通过修改传参来获取到对应的数据!
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("com.game.jmx.mbean:type=Test");
Test mbean = new Test();
mbs.registerMBean(mbean, name);
System.out.println("Waiting forever...");
Thread.sleep(Long.MAX_VALUE);
}
若是要启动远程连接此时就需要定义一个IP和端口
/**
* 开启JMX监控
*
* @throws Exception
*/
public void startJmx(int port) {
try {
String ip = InetAddress.getLocalHost().getHostAddress();//获得本机IP
LocateRegistry.createRegistry(port);
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + ip + ":" + port + "/jmxrmi");
JMXConnectorServer ser = JMXConnectorServerFactory.newJMXConnectorServer(url, null, server);
ser.start();
} catch (Exception e) {
JmxMgr.log.error("启动jmx错误,{}", e);
}
}
上述代码中的server就是MBeanServer。
ps:要开启远程监控的方式需要配置如下
如果只是本地类测试,只需要配置端口和ip即可
若要远程监控需要配置
找到文件 /tomcat/bin/catalina.sh
找到下面的内容
# —– Execute The Requested Command —————————————–
在其上,添加以下配置
authenticate,true 开启鉴权功能
access.file,权限文件路径
password.file,密码文件路径
将 JAVA_HOME/jre/lib/management 下面的 jmxremote.access 和jmxremote.password.template 拷贝到 tomcat conf目录下
1:jmxremote.password.template文件名修改为jmxremote.password。
2:修改两个文件的权限
chmod 600 jmxremote.access
chmod 600 jmxremote.password
此时jmx代理也编写完毕,此时就有两种方式来查看MBean对应的信息
第一种方式就是直接的打开Jconsole或者Jvisulevm来查看对应的mbean
第二种方式就是编码连接到jmx代理然后进行查看
这里说一下第二种方式
连接到jmx服务器
/**
* 客户端链接到远程jmx服务器
*/
public static MBeanServerConnection connectJmx(int jmxPort) {
MBeanServerConnection mbsc = null;
try {
//链接到远程JMX
String jmxAddress = InetAddress.getLocalHost().getHostAddress();//获得本机IP,远程的就是远程机器的IP地址
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + jmxAddress + ":" + jmxPort + "/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
mbsc = jmxc.getMBeanServerConnection();
} catch (Exception e) {
log.error("链接jmx服务器失败,错误{}", e);
}
return mbsc;
}
上述代码可以获取到对应的jmx远程连接,此时可以通过远程连接到操作对应的mbean了
如下:
//构建要查询的类
ObjectName objectName = new ObjectName("gs:name=com.server.game.jmx.mbean.Test");
MBeanInfo mBeanInfo = mbsc.getMBeanInfo(objectName);
//获取MBean的方法
TestMBean testMBean = MBeanServerInvocationHandler.newProxyInstance(mbsc, objectName, TestMBean.class, false);
String s = testMBean.printHello();
System.out.println(s);
获取内存的数据
//获取内存的使用情况
MemoryMXBean memBean = ManagementFactory.newPlatformMXBeanProxy(mbsc, ManagementFactory.MEMORY_MXBEAN_NAME, MemoryMXBean.class);
MemoryUsage heap = memBean.getHeapMemoryUsage();
//堆使用情况
long used = heap.getUsed();
long committed = heap.getCommitted();
至此,一个基于标准MBean的jmx监控就开发完毕了。
当然jmx的监控也没有这么简单,其中还有MBean与Mbean之间的通知的机制,同时也有其他动态的MBean,此种MBean的方式可以返回比较复杂的数据结构,不想MBean只能返回基本的数据类型。
昨天老大又说要返回一个对象!此刻,懵逼了!好吧,继续研究JMX!
jmx可以返回对象这种复杂的数据类型,这个叫MXBean 。 前提是返回的对象的父类中不能有Abstract类,否则会报错。报错的如下
javax.management.NotCompliantMBeanException:
com.server.game.jmx.mxbean.map.MapInfoMXBean:
Method com.server.game.jmx.mxbean.map.MapInfoMXBean.getMServer has parameter
or return type that cannot be translated into an open type
注册MBean的时候报错,其实就是在对返回的对象进行内省的时候判断不是接口而是Abstract就包上述错误了
源码如下:
private MBeanAnalyzer(Class> mbeanType,
MBeanIntrospector introspector)
throws NotCompliantMBeanException {
if (!mbeanType.isInterface()) {
throw new NotCompliantMBeanException("Not an interface: " +
mbeanType.getName());
} else if (!Modifier.isPublic(mbeanType.getModifiers()) &&
!Introspector.ALLOW_NONPUBLIC_MBEAN) {
throw new NotCompliantMBeanException("Interface is not public: " +
mbeanType.getName());
}
try {
initMaps(mbeanType, introspector);
} catch (Exception x) {
throw Introspector.throwException(mbeanType,x);
}
}
好吧!那就自己重写返回的对象,即可!
编写MXBean的方式和MBean的方式是一样的,只是将MBean接口改为MXBean接口即可。
总结:Jmx是很强大的一种jvm监控工具,我们在开发中还是必须要掌握的一种技能!