4.0 通知

2016-01-23 18:29:31 7,544 0

JMX API定义了一种机制,使得MBeans能够生成通知Notificationn,比如通知一个状态改变、一个检测到的事件或者问题。通知的作用是主动通知远程客户端。例如我们的程序出现了异常,或者CPU使用率过高,或者程序出现了死锁等一系列问题。这个时候我们希望程序能主动将这些问题发送给远程客户端,将这些问题记录下来,或者执行一些其他的报警操作。

通知的类型

在JMX中,通知通过类 javax.management.Notification来表示。因为通知有很多种,所以Notification有很多子类,用于细分不同类型的通知,如下:
Image.png

可以看到细分的通知种类有很多,最容易理解的是 AttributeChangedNotification。在前面我们已经讲解过MBean中可以定义属性和操作,表示的就是当属性发生变化时,我们可以发出的通知类型。
       每个通知都有一个源头。源头就是产生该通知的MBean的对象名。一个MBean只要检测条件的变化,就可以发送对应的通知。
       每个通知都有一个序列号编号。当通知的接收顺序很重要 并且 以错误的顺序处理通知可能会有风险时,该编号可以用于对来自相同通知源头的通知进行排序。序列编号可以是0,但是为每个来自特定MBean的通知 设置 递增的号码 会更好。举例来说,看一下AttributeChangedNotification的构造方法:

/**
     * Constructs an attribute change notification object.
     * In addition to the information common to all notification, the caller must supply the name and type
     * of the attribute, as well as its old and new values.
     *
     * @param source The notification producer, that is, the MBean the attribute belongs to.
     * @param sequenceNumber The notification sequence number within the source object.
     * @param timeStamp The date at which the notification is being sent.
     * @param msg A String containing the message of the notification.
     * @param attributeName A String giving the name of the attribute.
     * @param attributeType A String containing the type of the attribute.
     * @param oldValue An object representing value of the attribute before the change.
     * @param newValue An object representing value of the attribute after the change.
     */
public AttributeChangeNotification(Object source, long sequenceNumber, long timeStamp, String msg,
                                       String attributeName, String attributeType, Object oldValue, Object newValue)

source指的是生成这个通知的MBean实例,sequenceNumber指的是通知的序号。


通知的发送

很容易想到,既然我们MBean可以发送通知,那么对应的,肯定有一个通知的接受方。不过目前我们不讨论通知的接收方,只考虑如何发送通知。
     通常情况下,通知的发送方和通知的接收方是不在同一台物理机器上的,所以发送通知这个操作必然是需要进行网络传输的,而且我们还要监听通知的产生等等方面的问题。幸运的是,在JMX中,我们并不需要进行网络编程来发送通知。在JMX中,有一个NotificationBroadcasterSupport类,其已经帮助我们实现了发送一个通知需要考虑的各种问题:监听通知的产生、通知的发送等...。我们的MBean只需要继承这个类,就可以具备发送通知的功能。

一个MBean要想生成通知,那么它必须实现接口 NotificationEmitter 或者扩展 NotificationBroadcasterSupport。我们要关注的是以下两个方法:

public class NotificationBroadcasterSupport implements NotificationEmitter {
    ...
    public MBeanNotificationInfo[] getNotificationInfo(){...}
    public void sendNotification(Notification notification){...}
    ...
}

sendNotification方法:

发送一条通知,你需要构造javax.management.Notification或其子类(比如AttributeChangedNotification)的一个实例传入即可。

getNotificationInfo方法:

        前面提到的Notification的子类有很多种,这个方法是告诉JMX框架我们的MBean会发送哪几种类型的通知。如果我们在MBean中发送的通知类型,但是没有在这里声明,那么就是非法的。
        这个方法的返回值是MBeanNotificationInfo[],每个通知类型对应数组中的一个元素。MBeanNotificationInfo对象中维护的信息包括:通知类型,通知对应的java类的全名,以及一些描述信息等。

通知的实现:

Standard MBeans课程中描述的Hello MBean实现实际上已经实现了通知机制。只是,为了简便起见,相关代码在该课程中省略了。 Hello 的完整代码如下:

package com.tianshouzhi.jmx.notification;

import javax.management.AttributeChangeNotification;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
public class Hello extends NotificationBroadcasterSupport implements HelloMBean {

    public void sayHello() {
        System.out.println("hello, world");
    }

    public int add(int x, int y) {
        return x + y;
    }

    public String getName() {
        return this.name;
    }

    public int getCacheSize() {
        return this.cacheSize;
    }

    public synchronized void setCacheSize(int size) {
        int oldSize = this.cacheSize;
        this.cacheSize = size;

        System.out.println("Cache size now " + this.cacheSize);
        //构建通知
        Notification n = new AttributeChangeNotification(this,
                sequenceNumber++, System.currentTimeMillis(),
                "CacheSize changed", "CacheSize", "int", oldSize,
                this.cacheSize);
        //发送通知
        sendNotification(n);
    }

    //返回这个MBean将会发送的通知类型信息
    @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 };
    }

    private final String name = "Reginald";
    private int cacheSize = DEFAULT_CACHE_SIZE;
    private static final int DEFAULT_CACHE_SIZE = 200;

    private long sequenceNumber = 1;
}

Hello MBean扩展了NotificationBroadcasterSupport类。NotificationBroadcasterSupport 实现了 NotificationEmitter 接口。

各个操作和各个属性的设置方式和标准MBean那个例子相同,唯一的例外是CacheSize的属性的setter方法现在定义了一个 oldSize值。该值记录了在对CacheSize属性执行set操作之前,CacheSize属性的值。

通知从JMX class AttributeChangeNotification构造而来,名字为 n,AttributeChangeNotification扩展了javax.management.Notification。我们在方法setCacheSize()中构造该通知,携带下列信息。该信息被作为参数传给 AttributeChangeNotification

  • 通知源头的对象名,也就是 Hello MBean,用this代表它。

  • 一个序列号,也就是sequenceNumber,它被设置为1,然后逐渐递增。

  • 一个时间戳。

  • 通知消息的内容。

  • 被改变的属性的名字,在这里,为CacheSize

  • 被改变的属性的类型。

  • 被改变的属性的旧值,在这里,为oldSize

  • 被改变的属性的新值,在这里,为this.cacheSize

该通知,n,然后被传递给 NotificationBroadcasterSupport.sendNotification() 方法。

最后,定义了 MBeanNotificationInfo 实例,它用于描述该MBean为特定类型的通知 生成的不同通知的特征。

关于MBeanNotificationInfo的提示

"public MBeanNotificationInfo[] getNotificationInfo()"方法来自顶层接口 javax.management.MBeanNotificationInfo[] getNotificationInfo()。只在注册该MBean的时候,调用一次,用于获取该MBean为特定类型的通知 生成的不同通知的特征。

如果想要接收某种类型的消息,那么需要到 MBean Server中订阅(JMX Client也可以到MBean Server中订阅)。

本例中,该方法实现为:

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 };
}

这个方法只体现了一个类型的通知,AttributeChangeNotification.ATTRIBUTE_CHANGE。没有体现出多种类型的通知。实际应用中,该方法可能是这样的:

public MBeanNotificationInfo[] getNotificationInfo() {
    String[] types = new String[] { AttributeChangeNotification.ATTRIBUTE_CHANGE, “XXX”, "YYY" ... };
    String name = AttributeChangeNotification.class.getName();
    String description = "An attribute of this MBean has changed";
    //
    MBeanNotificationInfo info1 = new MBeanNotificationInfo(
            types,
            name,
            description);
    MBeanNotificationInfo info2 = new MBeanNotificationInfo(...)
    return new MBeanNotificationInfo[] { info1, info2, info3, ... };
}

运行该MBean Notification例子

1、运行程序。

2、使用JConsole连接。查看MBeans标签页。

Image.png

可以看到名称为Hello的MBean多了一个Notifications。

3、点击Subscribe按钮,表示要订阅通知。

4、修改CacheSize的值

Image.png

修改之后点击refresh按钮。

5、刷新之后,我们可以看到Notifications[0]变成了Notifications[1],表示接受到了一条消息。



上一篇:3.2 MXBeans 下一篇:5.0 远程管理