JMX整理
What and Why JMX
JMX的全称为Java Management Extensions. 顾名思义,是管理Java的一种扩展。这种机制可以方便的管理正在运行中的Java程序。常用于管理线程,内存,日志Level,服务重启,系统环境等。
试想,一个正在运行中的程序,我们如果想改变程序中的一些属性,可以通过什么方法呢?可能有这么几个方法:
对于服务器式的程序,可以制作管理页面,通过HTTP post与servlet来更改服务器端程序的属性。
对于服务器式的程序,还可以通过SOAP方式。但这需要程序开启了SOAP端的服务。
可以使用RMI远程调用。但这需要设计开启RMI服务。
如果是SWT或Swing的程序,则可以通过设计UI管理界面,使用户可以和程序内部交互。
还有一种方式,是将可改变的属性放入配置文件XML,properties或数据库,程序轮询配置文件,以求获取最新的配置。
上面几个方法都是常见,但却无法通用的。所谓通用,是指解决方案符合一个标准,使得任何符合此标准的工具都能解析针对此标准的方案实现。这样A公司设计的方案,B公司可以根据标准来解析。JMX就是Java管理标准。
JMX的构成
JMX由三部分组成:
程序端的Instrumentation, 我把它翻译成可操作的仪器。这部分就是指的MBean. MBean类似于JavaBean。最常用的MBean则是Standard MBean和MXBean.
程序端的JMX agent. 这部分指的是MBean Server. MBean Server则是启动与JVM内的基于各种协议的适配器。用于接收客户端的调遣,然后调用相应的MBeans.
客户端的Remote Management. 这部分则是面向用户的程序。此程序则是MBeans在用户前投影,用户操作这些投影,可以反映到程序端的MBean中去。这内部的原理则是client通过某种协议调用agent操控MBeans.
JMX agent与Remote Management之间是通过协议链接的,这协议可能包含:
HTTP
SNMP
RMI
IIOP
JMX agent中有针对上面协议的各种适配器。可以解析通过相应协议传输过来的数据。Remote Management client则可以用现成的工具,如JConsole, 也可以自己书写java code。
接下来,我们看是一步一步,通过代码示例来熟悉JMX各种特性。
受监管的程序
JMX是用于管理java程序的,为了试验,我们首先需要写一个小程序Echo。然后加入JMX对此程序进行监管。这个程序就是每隔10秒钟,输出一个预先定义好的Message。
首先定义Message类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public class Message { private String title, body, by; public Message() { title= "none" ; body= "none" ; by= "none" ; } public String getTitle() { return title; } public void setTitle(String title) { this .title = title; } public String getBody() { return body; } public void setBody(String body) { this .body = body; } public String getBy() { return by; } public void setBy(String by) { this .by = by; } public void echo() { System.out.println( "<" +title+ ">" ); System.out.println(body); System.out.println( "by " + by); } } |
定义Echo类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public class Echo { public static Message msg = new Message(); public static boolean running= true ; public static boolean pause= false ; public static void main(String[] args) { // 开启JMX Agent。如果不需要JMX,只是单独运行程序,请屏蔽掉下面这行代码。 new MessageEngineAgent().start(); while (running) { try { Thread.sleep( 10000 ); } catch (InterruptedException e) { e.printStackTrace(); } if (!pause) msg.echo(); } } } |
执行Echo,得到每过10秒钟,则会输出一个消息:
<none>
none
by none
MBean
接下来,开始设计管理程序的MBean. 在设计MBean之前,必须要先了解MBean都包括哪几种。MBean包含:
Standard MBean
Dynamic MBean
Open MBean
Model MBean
MXBean
最常用最简单的两个就是Standard MBean与MXBean. 首先搞清楚,MBean和MXBean的区别是什么。
Standard MBean与MXBean的区别
这里有一些细节,列出了两只的区别http://docs.oracle.com/javase/7/docs/api/javax/management/MXBean.html 。它 们最根本的区别是,MXBean在Agent与Client之间会将自定义的Java类型转化为Java Open Type. 这样的好处是Client无需获取MXBean的接口程序,便可访问和操作MXBean的投影。如果使用MBean, client则必须先将MBean的接口程序放到classpath中,否则无法解析MBean中自定义类型。
基于上述原因,我将使用MXBean做为例子。实际上,JVM自带的几乎全是MXBean。
实现
定义MXBean的接口,注意命名规则,必须以MXBean结尾。
1
2
3
4
5
6
7
8
9
10
11
|
public interface MessageEngineMXBean { //结束程序。 public void stop(); //查看程序是否暂停。 public boolean isPaused(); //暂停程序或者继续程序。 public void pause( boolean pause); public Message getMessage(); //修改message public void changeMessage(Message m); } |
实现部分。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public class MessageEngine implements MessageEngineMXBean { private final Message message = Echo.msg; @Override public void stop() { Echo.running = false ; } @Override public boolean isPaused() { return Echo.pause; } @Override public void pause( boolean pause) { Echo.pause = pause; } @Override public Message getMessage() { return this .message; } @Override public void changeMessage(Message m) { this .message.setBody(m.getBody()); this .message.setTitle(m.getTitle()); this .message.setBy(m.getBy()); } } |
Notification
在JMX中,还有一个重要的概念是Notification。构成Notification的几个接口是:
NotificationEmitter, 只要实现此接口,就可以发出Notification和订阅Notification. 类NotificationBroadcasterSupport则实现了NotificationEmitter.
NotificationListener, 实现此接口的可以订阅JMX的Notification。
Notification, 消息本身。
修改MessageEngine, 使它在pause的时候发送通知给订阅者。我把修改的部分贴上。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
public class MessageEngine extends NotificationBroadcasterSupport implements MessageEngineMXBean { private long sequenceNumber = 1 ; ... ... ... ... public MessageEngine() { addNotificationListener( new NotificationListener() { @Override public void handleNotification(Notification notification, Object handback) { System.out.println( "*** Handling new notification ***" ); System.out.println( "Message: " + notification.getMessage()); System.out.println( "Seq: " + notification.getSequenceNumber()); System.out.println( "*********************************" ); } }, null , null ); } ... ... ... ... @Override public void pause( boolean pause) { Notification n = new AttributeChangeNotification( this , sequenceNumber++, System.currentTimeMillis(), "Pause changed" , "Paused" , "boolean" , Echo.pause, pause); Echo.pause = pause; this .sendNotification(n); } ... ... ... ... // 规定可以发送的Notification Type,不在Type list中的Notification不会被发送。 @Override public MBeanNotificationInfo[] getNotificationInfo() { String[] types = new String[]{ AttributeChangeNotification.ATTRIBUTE_CHANGE }; String name = AttributeChangeNotification. class .getName(); String description = "An attribute of this MBean has changed" ; MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description); return new MBeanNotificationInfo[]{info}; } } |
Client端如何使用Notification,可以查看后面的Client一节。
JMX Agent
如果说Agent只是被Local使用,比如本地的JConsole,只需要开启MBeanServer,并注册MBean即可。不需要配置协议适配器。但如果需要远程管理,比如远程的JConsole或者自定义的管理器,则还需要配置两者相互打交道的协议适配器。
1
2
3
4
5
6
7
8
9
10
11
12
|
public class MessageEngineAgent { public void start() { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { ObjectName mxbeanName = new ObjectName( "com.example:type=MessageEngine" ); MessageEngineMXBean mxbean = new MessageEngine(); mbs.registerMBean(mxbean, mxbeanName); } catch (Exception e) { e.printStackTrace(); } } } |
因为java默认自带的了JMX RMI的连接器。所以,只需要在启动java程序的时候带上运行参数,就可以开启Agent的RMI协议的连接器。
1
2
3
4
|
java -Dcom.sun.management.jmxremote.port = 9999 \ -Dcom.sun.management.jmxremote.authenticate = false \ -Dcom.sun.management.jmxremote.ssl = false \ jmx.Echo |
认证与授权
JMX的认证与授权是非常必要的,我们不可能允许任何client都能连接我们的Server。JMX的认证和授权可以复杂的使用LDAP, SSL。也可以使用最简单的文件存储用户信息方式。本文作为启蒙,只给出最简单的认证方式。
在java启动的时候,添加运行参数:
1
2
3
4
5
6
|
java -Dcom.sun.management.jmxremote.port = 9999 \ -Dcom.sun.management.jmxremote.authenticate = true \ -Dcom.sun.management.jmxremote.password.file = pathTo/my.password \ -Dcom.sun.management.jmxremote.access.file = pathTo/my.access \ -Dcom.sun.management.jmxremote.ssl = false \ jmx.Echo |
my.password里面定义了用户名和密码:
1
2
|
user1 password1 user2 password2 |
my.access里面定义了用户授权信息:
1
2
3
4
|
user1 readOnly user2 readWrite \ create jmx.*,javax.management.timer.* \ unregister |
更详细的内容可以从这里找到: http://docs.oracle.com/javase/7/docs/technotes/guides/management/agent.html 。
现在可以启动程序了。启动以后,我们使用下面的Client来连接我们写的JMX Agent.
JMX Client
JConsole
JDK提供了一个工具在jdk/bin目录下面,这就是JConsole。使用JConsole可以远程或本地连接JMX agent。如下图所以:
无论是远程还是本地,连接进去所看到的都一样。进去MBeans面板以后,找到MessageEngine。MessageEngine下面有
Attributes,
Operations和Notification。可以浏览MessageEngine中的Attributes并更改那些可写的属性。也可以执行
Operations下面的stop, pause方法。此外,必须订阅Notifications才能收到消息。
JConsole有缺点,它只能对MXBean中的主要基本类型做修改,但不能修改复杂类型。
Custom Client
我们也可以用java写client调用Agent。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
public class Client implements NotificationListener { public static void main(String[] args) { try { new Client().start(); } catch (Exception e) { e.printStackTrace(); } } public void start() throws Exception { // 如果agent不做配置的话,默认jndi path为jmxrmi JMXServiceURL url = new JMXServiceURL( "service:jmx:rmi://localhost/jndi/rmi://localhost:9999/jmxrmi" ); JMXConnector jmxc = JMXConnectorFactory.connect(url, null ); MBeanServerConnection server = jmxc.getMBeanServerConnection(); ObjectName mbeanName = new ObjectName( "com.example:type=MessageEngine" ); // 订阅Notification server.addNotificationListener(mbeanName, this , null , null ); // 访问paused属性。 boolean paused = (Boolean)server.getAttribute(mbeanName, "Paused" ); System.out.println(paused); if (!paused) { server.invoke(mbeanName, "pause" , new Object[]{ true }, new String[]{ "boolean" }); } // 构建一个jmx.Message类型实例。 CompositeType msgType = new CompositeType( "jmx.Message" , "Message Class Name" , new String[]{ "title" , "body" , "by" }, new String[]{ "title" , "body" , "by" }, new OpenType[]{SimpleType.STRING,SimpleType.STRING,SimpleType.STRING}); CompositeData msgData = new CompositeDataSupport(msgType, new String[]{ "title" , "body" , "by" }, new Object[]{ "Hello" , "This is a new message." , "xpbug" }); // 调用changeMessage方法 server.invoke(mbeanName, "changeMessage" , new Object[]{msgData}, new String[]{CompositeData. class .getName()}); server.invoke(mbeanName, "pause" , new Object[]{ false }, new String[]{ "boolean" }); // 访问修改后的Message属性。 msgData = (CompositeData)server.getAttribute(mbeanName, "Message" ); System.out.println( "The message changes to:" ); System.out.println(msgData.get( "title" )); System.out.println(msgData.get( "body" )); System.out.println(msgData.get( "by" )); Thread.sleep( 1000 * 10 ); } @Override public void handleNotification(Notification notification, Object handback) { System.out.println( "*** Handling new notification ***" ); System.out.println( "Message: " + notification.getMessage()); System.out.println( "Seq: " + notification.getSequenceNumber()); System.out.println( "*********************************" ); } } |
运行一下client,看看都发生了什么。
源码下载
http://pan.baidu.com/s/1sjLKewX
来自:http://my.oschina.net/xpbug/blog/221547
JMX整理的更多相关文章
- 从零开始玩转JMX(四)——Apache Commons Modeler & Dynamic MBean
Apache Commons Modeler 前面的Model MBean的创建方式看上去特别复杂,一个简单功能的类ModelMBeanUtils 写了很多代码,那有木有简单点的方式呢,答案是肯定的, ...
- 从零开始玩转JMX(三)——Model MBean
Model MBean 相对于Standard MBean,Model MBean更加灵活.如果我们不能修改已有的Java类,那么使用Model MBean是不错的选择. Model MBean也是一 ...
- 从零开始玩转JMX(二)——Condition
Notification 一个MBean提供的管理接口允许代理对其管理资源进行控制和配置.然而,对管理复杂的分布式系统来说,这些接口知识提供了一部分功能.通常,管理应用程序需要对状态变化或者当特别情况 ...
- 从零开始玩转JMX(一)——简介和Standard MBean
JMX的全称为Java Management Extensions. 顾名思义,是管理Java的一种扩展.这种机制可以方便的管理.监控正在运行中的Java程序.常用于管理线程,内存,日志Level,服 ...
- 国外程序员整理的Java资源大全分享
Java 几乎是许多程序员们的入门语言,并且也是世界上非常流行的编程语言.国外程序员 Andreas Kull 在其 Github 上整理了非常优秀的 Java 开发资源,推荐给大家. 译文由 Imp ...
- 基于java平台的常用资源整理
这里整理了基于java平台的常用资源 翻译 from :akullpp | awesome-java 大家一起学习,共同进步. 如果大家觉得有用,就mark一下,赞一下,或评论一下,让更多的人知道.t ...
- 这里整理了基于java平台的常用资源
这里整理了基于java平台的常用资源 翻译 from :akullpp | awesome-java 大家一起学习,共同进步. 如果大家觉得有用,就mark一下,赞一下,或评论一下,让更多的人知道.t ...
- 【转】国外程序员整理的Java资源大全
Java几乎是许多程序员们的入门语言,并且也是世界上非常流行的编程语言.国外程序员Andreas Kull在其Github上整理了非常优秀的Java开发资源,推荐给大家.译文由ImportNew- 唐 ...
- 【整理】Java 8新特性总结
闲语: 相比于今年三月份才发布的Java 10 ,发布已久的Java 8 已经算是老版本了(传闻Java 11将于9月25日发布....).然而很多报道表明:Java 9 和JJava10不是 LTS ...
随机推荐
- bzoj4400: tjoi2012 桥
先传代码再填坑 #include <iostream> #include <cstdio> #include <cmath> #include <cstrin ...
- Redis 数据类型-List
lpush/rpush/lrange 127.0.0.1:6379> LPUSH list01 1 2 3 4 5 (integer) 5 127.0.0.1:6379> LRANGE l ...
- [学习笔记]tarjan求割边
上午打模拟赛的时候想出了第三题题解,可是我不会求割边只能暴力判割边了QAQ 所以,本文介绍求割边(又称桥). 的定义同求有向图强连通分量. 枚举当前点的所有邻接点: 1.如果某个邻接点未被访问过,则访 ...
- 【BZOJ-3343】教主的魔法 分块
3343: 教主的魔法 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 950 Solved: 414[Submit][Status][Discuss ...
- 【poj3084】 Panic Room
http://poj.org/problem?id=3084 (题目链接) 题意 一个房子里面有m个房间,一些房间之间有门相连,而门的开关只在一个房间有,也就是说只有一个房间可以控制该扇门的开关.现在 ...
- hdu 1757 矩阵
用矩阵表示状态,矩阵乘法的就是状态之间的变换 作一个vector: 要求的就是一个矩阵A,使得上面那个vector乘以A之后变成 解得A= [不知道用逆矩阵能不能直接求出A Ref:http://bl ...
- POJ1236Network of Schools(强连通分量 + 缩点)
题目链接Network of Schools 参考斌神博客 强连通分量缩点求入度为0的个数和出度为0的分量个数 题目大意:N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后 ...
- django rest framework
Django-Rest-Framework 教程: 4. 验证和权限 作者: Desmond Chen, 发布日期: 2014-06-01, 修改日期: 2014-06-02 到目前为止, 我们的AP ...
- CSS-论css如何纯代码实现内凹圆角
background-image: radial-gradient(200px at 50px 0px, #fff 50px, #4169E1 50px); 这是做内凹圆角的核心代码,就是背景图的ra ...
- css005 用层叠管理多样式
css005 用层叠管理多样式 当一个元素继承多个样式时,最近的祖先样式胜出(通俗一点就是自己有就用自己的,自己没有找parent,parent没有找grandprent,再没有就一级一级网上找) 当 ...