文章目录
- 1. 定义和存在的意义
- 2. 架构
- 2.1 Instrumentation
- 2.2 JMX Agent
- 2.3 Remote Management
- 3. 启动和连接
- 3.1 注册MBean
- 3.2 有两个方式启动JMX Agent
- 3.3 Remote Management(客户端)
- 4. MBeanServerConnection使用
- 4.1 列出所有的MBean
- 4.2 列出所有的Domain
- 4.3 MBean计数
- 4.4 获取和设置属性
- 4.5 调用方法
- 4.6 获取MBeanInfo
1. 定义和存在的意义
JMX是Java Management Extention的缩写,本质的出发点是让外部能获取、设置应用的信息及操作。如果是Web应用可以通过HTTP接口暴露,如果RPC应用可以通过RPC调用暴露,但是不通用。JMX就是为这类管理接口提供一个统一的访问方式。
2. 架构
JMX在架构上分为3层:
- Instrumentation
- JMX agent
- Remote management
2.1 Instrumentation
Instrumentation提供了MBean创建的规范,JDK自带了一组叫做MXBean的特殊MBean,对外暴露了一些JVM信息及操作。
2.2 JMX Agent
JMX Agent用来管理Instrument, JMX Agent的核心是MBeanServer(用来注册MBean),并至少提供一组adaptor和connector(可以理解为通信协议和通信方式,允许外部程序或者客户端和JMX Agent通信)
2.3 Remote Management
可以理解为JMX Agent的客户端,通过不同的adapter和connect(协议和通信方式)连接到JMX Agent。
3. 启动和连接
3.1 注册MBean
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
String domain = "MyMBean";
// 注册hello
ObjectName helloName = new ObjectName(domain + ":name=hello");
server.registerMBean(new Hello(),helloName);
3.2 有两个方式启动JMX Agent
- 使用JVM参数
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
- 使用Java代码
String domain = "jmxrmi"
int rmiPort = 1099;
Registry registry = LocateRegistry.createRegistry(rmiPort);
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + rmiPort + "/" + domain);
JMXConnectorServer jmxConnector = JMXConnectorServerFactory.newJMXConnectorServer(url,null,server);
jmxConnector.start();
如果是代码或者是远程连接JMX Agent,后续会用到JMXServiceURL的地址。和使用Java代码创建不同,JVM参数的domain值固定为jmxrmi
3.3 Remote Management(客户端)
客户端的方式也有很多,这里介绍两种
-
JConsole 有两种选项,本地进程,可以选择进程ID连接,远程进程要使用JMXServiceURL里的地址
-
Java代码
String domain = "jmxrmi";
int rmiPort = 1099;
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + rmiPort + "/" + domain);
JMXConnector jmxc = JMXConnectorFactory.connect(url);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
4. MBeanServerConnection使用
4.1 列出所有的MBean
Set<ObjectInstance> ins = mbsc.queryMBeans(null,null);
for(ObjectInstance i : ins) {System.out.println("object: " + i.getObjectName());
}
4.2 列出所有的Domain
String[] domains = mbsc.getDomains();
for (String d : domains) {System.out.println(d);
}
4.3 MBean计数
System.out.println("MBeanCount:" + mbsc.getMBeanCount());
4.4 获取和设置属性
String domain = "MyMBean";
ObjectName helloName = new ObjectName(domain + ":name=hello");
System.out.println("getAttribute:--->" + mbsc.getAttribute(helloName, "Slogan")); // 获取
mbsc.setAttribute(helloName, new Attribute("Slogan", "" + System.nanoTime())); // 设置
System.out.println("getAttribute after modified--->" + mbsc.getAttribute(helloName, "Slogan")); // 获取
4.5 调用方法
有两种方式
- 使用MBeanServerConnection
String domain = "MyMBean";
ObjectName helloName = new ObjectName(domain + ":name=hello");mbsc.invoke(helloName, "printHello", new String[]{"shit"}, new String[]{String.class.getName()}); // 没有返回值
Object resp = mbsc.invoke(helloName, "daydream", new Integer[]{5000}, new String[]{Integer.class.getName()}); // 返回值
System.out.println("daydream:--->" + resp);
- 使用MBeanServerInvocationHandler生成代理类
String domain = "MyMBean";
ObjectName helloName = new ObjectName(domain + ":name=hello");HelloMBean proxy = MBeanServerInvocationHandler.newProxyInstance(mbsc,helloName,HelloMBean.class,false);
System.out.println("proxy get attribute:" + proxy.getSlogan());
System.out.println("proxy invoke:" + proxy.daydream(9999));
4.6 获取MBeanInfo
String domain = "MyMBean";
ObjectName helloName = new ObjectName(domain + ":name=hello");MBeanInfo beanInfo = mbsc.getMBeanInfo(helloName);
System.out.println("class name:" + beanInfo.getClassName()); // MBean实现类MBeanAttributeInfo[] attrinfos = beanInfo.getAttributes(); // MBean的属性
for(MBeanAttributeInfo a: attrinfos) {System.out.println("attribute name:" + a.getName());
}MBeanOperationInfo[] operationInfos = beanInfo.getOperations(); // MBean上的操作
for(MBeanOperationInfo o: operationInfos) {System.out.println("operation name:" + o.getName());
}