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由三部分组成:

  1. 程序端的Instrumentation, 我把它翻译成可操作的仪器。这部分就是指的MBean. MBean类似于JavaBean。最常用的MBean则是Standard MBean和MXBean.
  2. 程序端的JMX agent. 这部分指的是MBean Server. MBean Server则是启动与JVM内的基于各种协议的适配器。用于接收客户端的调遣,然后调用相应的MBeans.
  3. 客户端的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包含:

  1. Standard MBean
  2. Dynamic MBean
  3. Open MBean
  4. Model MBean
  5. 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的几个接口是:

  1. NotificationEmitter, 只要实现此接口,就可以发出Notification和订阅Notification. 类NotificationBroadcasterSupport则实现了NotificationEmitter.
  2. NotificationListener, 实现此接口的可以订阅JMX的Notification。
  3. 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("*********************************");

            }

        }, nullnull);

    }

    ... ...

    ... ...

    @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, thisnullnull);

        

        // 访问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

相关:Jetty源码学习6-JMX

时间: 2024-12-29 23:23:12

JMX整理的相关文章

从零开始玩转JMX(四)——Apache Commons Modeler &amp; Dynamic MBean

Apache Commons Modeler 前面的Model MBean的创建方式看上去特别复杂,一个简单功能的类ModelMBeanUtils 写了很多代码,那有木有简单点的方式呢,答案是肯定的,这里就引出了Apache Commons Modeler(使用这个需要在classpath中导入commons-modeler-2.0.1.jar以及modeler的依赖项目commons-logging-1.1.3.jar,下载地址:http://commons.apache.org/proper

从零开始玩转JMX(一)——简介和Standard MBean

从零开始玩转JMX(一)--简介和Standard MBean JMX超详细解读 参考资料 JMX整理 JMX简介 http://blog.csdn.net/DryKillLogic/article/category/762777 用Apache的commons-modeler来辅助开发JMX

这里整理了基于java平台的常用资源

这里整理了基于java平台的常用资源 翻译 from :akullpp | awesome-java 大家一起学习,共同进步. 如果大家觉得有用,就mark一下,赞一下,或评论一下,让更多的人知道.thanks. 构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化的方式进行配置,所以维护起来相当困难. Gradle:Gradle采用增量构建.Gra

【转】国外程序员整理的Java资源大全

Java几乎是许多程序员们的入门语言,并且也是世界上非常流行的编程语言.国外程序员Andreas Kull在其Github上整理了非常优秀的Java开发资源,推荐给大家.译文由ImportNew- 唐尤华翻译完成. 以下为具体资源列表. 构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化的方式进行配置,所以维护起来相当困难. Gradle:Grad

监控应用服务器使用JMX监控Tomcat (转收藏)

前言:做了一个监控应用服务器的项目(支持Tocmat.WebSphere.WebLogic各版本), 过程也算是磕磕绊绊,由于网上缺少相关资料,或者深陷于知识的海洋难以寻觅到有效的资料,因而走过不少弯路,遇过不少困难.为了留下点印记,给后来人留下 点经验之谈,助之少走弯路,故将这些经验整理出来,与大家分享.水平有限,难免疏漏,还望指正.如有疑问,欢迎留言,或者加入Q群参与讨 论:35526521. 一.激活Tomcat的JMX远程配置 要通过JMX远程监控Tomcat,首先需要激活Tomcat的

ehcache常用API整理

博客分类: java CacheXMLLinuxEclipsejunit 鉴于csdn的blog的不稳定, 及混乱的编辑器, 和无上传功能, 遂决定彻底投诚javaeye的blog. 数月前整理的一个东西, 作为cache的扫盲文档.参考了它的官方文档. 对ehcache感兴趣的兄台可以参考. 附件为eclipse项目, 直接导入, 运行test目录下的junit testcase, 可一目了然. 一 ehcache API: 1: Using the CacheManager 1.1所有ehc

国外程序员整理的Java资源大全分享

Java 几乎是许多程序员们的入门语言,并且也是世界上非常流行的编程语言.国外程序员 Andreas Kull 在其 Github 上整理了非常优秀的 Java 开发资源,推荐给大家. 译文由 ImportNew- 唐尤华翻译完成. 以下为具体资源列表. 构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven 使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven 优于 Apache Ant.后者采用了一种过程化的方式进行配置,所以维护起来相当困难.

Zabbix利用JMX监控多实例Tomcat运行状态

自使用Zabbix监控系统以来,一直想用JMX来监控Tomcat,但是一直都没配置成功,总有一些问题,监控端的报错又很抽象,搜索网上大都是复制粘贴之产物,或者是缺斤短两之网文,但是一直都没放弃,至今终于配置成功,并且成功获取数据,形成图形,现在把自己解决问题的过程和配置的一些心得整理成文. 环境介绍: Centos 6.5 Zabbix 2.2.15 Tomcat 7.0.68 监控JMX配置步骤 1.在zabbix服务器上安装配置zabbix-java-gateway,并且配置相关参数. 2.

【整理】Java 8新特性总结

闲语: 相比于今年三月份才发布的Java 10 ,发布已久的Java 8 已经算是老版本了(传闻Java 11将于9月25日发布....).然而很多报道表明:Java 9 和JJava10不是 LTS 版本,和过去的 Java 大版本升级不同,它们只有半年左右的开发和维护期.而未来的 Java11,也就是 18.9 LTS,才是 Java 8 之后第一个 LTS 版本(得到 Oracle 等商业公司的长期支持服务).所以Java 8 就成了最新的一次LTS版本升级,这也是为什么Java开发者对J