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类。

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类

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结尾。

public interface MessageEngineMXBean {
    //结束程序。
    public void stop();
    //查看程序是否暂停。
    public boolean isPaused();
    //暂停程序或者继续程序。
    public void pause(boolean pause);
    public Message getMessage();
    //修改message
    public void changeMessage(Message m);
}

 

实现部分。

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的时候发送通知给订阅者。我把修改的部分贴上。

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或者自定义的管理器,则还需要配置两者相互打交道的协议适配器。

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协议的连接器。

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启动的时候,添加运行参数:

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里面定义了用户名和密码:

user1 password1
user2 password2

 

my.access里面定义了用户授权信息:

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。

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 

https://my.oschina.net/xpbug/blog/221547

 

时间: 2024-10-26 19:39:17

JMX整理的相关文章

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

JMX的全称为Java Management Extensions. 顾名思义,是管理Java的一种扩展.这种机制可以方便的管理.监控正在运行中的Java程序.常用于管理线程,内存,日志Level,服务重启,系统环境等. 简介 基本术语 MBean:是Managed Bean的简称,可以翻译为"管理构件".在JMX中MBean代表一个被管理的资源实例,通过MBean中暴露的方法和属性,外界可以获取被管理的资源的状态和操纵MBean的行为.事实上,MBean就是一个Java Object

从零开始玩转JMX(二)——Condition

Notification 一个MBean提供的管理接口允许代理对其管理资源进行控制和配置.然而,对管理复杂的分布式系统来说,这些接口知识提供了一部分功能.通常,管理应用程序需要对状态变化或者当特别情况发生变化时作出反映.Notification起到了MBean之间的沟通桥梁的作用.JMX Notification模型和Java Event模型类似,将一些重要的信息,状态的转变,数据的变更传递给Notification Listener,以便资源的管理. 通知模型仅仅涉及了在同一个JMX代理中的管

从零开始玩转JMX(三)——Model MBean

Model MBean 相对于Standard MBean,Model MBean更加灵活.如果我们不能修改已有的Java类,那么使用Model MBean是不错的选择. Model MBean也是一种专门化的动态管理构件.它是预制的.通用的和动态的 MBean 类,已经包含了所有必要缺省行为的实现,并允许在运行时添加或覆盖需要定制的那些实现.JMX规范规定该类必须实现为javax.management.modelmbean.RequiredModelMBean,管理者要做的就是实例化该类,并配

jmx的简单学习

背景 前段时间在看btrace源码和jdk一些源码的时候,经常会看到一些jmx的相关内容.以前对jmx基本是一片空白区,花了点时间学习记录下.   过程 jmx总体架构图:  说明:  1.  Agent : javax.management.MBeanServer实现了Agent的功能,以标准的方式给出了管理系统访问 JMX 框架的接口 2. SubAgent: javax.management.MBeans实现了SubAgent的功能,以标准的方式给出了 JMX 框架访问资源的接口 MBea

[码]国外大牛整理的Java资源 !

先码为敬. Java几乎是许多程序员们的入门语言,并且也是世界上非常流行的编程语言.国外程序员Andreas Kull在其Github上整理了非常优秀的Java开发资源,推荐给大家. [编者按]Java几乎是许多程序员们的入门语言,并且也是世界上非常流行的编程语言.国外程序员Andreas Kull在其Github上整理了非常优秀的Java开发资源,推荐给大家.译文由ImportNew- 唐尤华翻译完成. 以下为具体资源列表. 构建 这里搜集了用来构建应用程序的工具. Apache Maven:

京东区域表整理

目前京东API文档里貌似还没开放京东配送区域查询的相应接口,所以需要自己动手了.通过对京东订单提交页显示的区域信息抓取,得到所有省份,城市,县区信息,再进行了一下整理,得到了这份京东区域表脚本,希望对做京东店铺App接入的人有帮助.打包下载

如何整理IE浏览器收藏夹

  第一步.在Windows 7系统下,打开IE9以后,依次单击"收藏夹"按钮."添加到收藏夹"按钮旁边的箭头和"整理收藏夹". 第二步.在"整理收藏夹"对话框中,将显示收藏夹链接和文件夹列表.从这里可以进行如下操作: 打开文件夹:单击文件夹将其展开,然后查看其包含的链接. 创建新文件夹:单击"新建文件夹",键入新文件夹的名称,然后按 Enter. 移动收藏夹:单击链接或文件夹,然后将其拖动到新的位置或文件

Work Like Alibaba系列分享资料整理(含PDF、视频、文字):持续更新中

阿里巴巴逐年增加的双11营业额和财年集团收入的背后隐藏着怎样的秘密?这18年来,它又是用怎样的工作方法.工作形式打造出高效.创新的企业帝国.带你全方位了解阿里的开发.产品.运营.销售是怎样协同.工作,我们还会邀请企业来实战分享,他们怎样Work Like Alibaba?取得了怎样的成果? Work like alibaba通过线下沙龙.线上直播.内容输出三个维度,携手阿里云的典型企业用户,联合阿里云.钉钉阿里产品,将阿里的前沿产品技术理念.敏捷研发模式.智能运维方法.智能办公.移动办公等渐渐渗

网站数据收集、整理、分析的方法和技巧

中介交易 SEO诊断 淘宝客 云主机 技术大厅 任务要求: 2010年10月18日中午12:00,入门任务第二期的任务开始,任务如下,对当前网络下的所有链接平台进行数据的收集整理和分析. 任务目的: 这次任务主要是锻炼我们的是几个力:执行力,耐力,分析能力,吃苦能力,这个是考验一个人工作是不是有耐心,会不会去动脑做事情,在收集的过程中,总是复制,粘贴这些枯燥无味并且重复性的工作,也是对一个人体力和眼力的考验.这个工作在第一个任务中也有对这方面的考验. 收集平台和整理平台可以说是另外一个力:苦力,