对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

通知

Spring的JMX功能包括对JMX通知的全面支持。spring-doc.cadn.net.cn

注册通知监听器

Spring的JMX支持使注册任意数量的 NotificationListeners 与任意数量的MBeans(这包括由Spring的MBeanExporter导出的MBeans以及通过其他机制注册的MBeans)变得非常容易。例如,考虑这样一个场景:每次目标MBean的属性发生变化时,都希望收到通知(通过Notification)。下面的例子会将通知写入控制台:spring-doc.cadn.net.cn

package com.example;

import javax.management.AttributeChangeNotification;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;

public class ConsoleLoggingNotificationListener
		implements NotificationListener, NotificationFilter {

	public void handleNotification(Notification notification, Object handback) {
		System.out.println(notification);
		System.out.println(handback);
	}

	public boolean isNotificationEnabled(Notification notification) {
		return AttributeChangeNotification.class.isAssignableFrom(notification.getClass());
	}

}

以下示例将 ConsoleLoggingNotificationListener(在前面的示例中定义)添加到 notificationListenerMappingsspring-doc.cadn.net.cn

<beans>

	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
		<property name="beans">
			<map>
				<entry key="bean:name=testBean1" value-ref="testBean"/>
			</map>
		</property>
		<property name="notificationListenerMappings">
			<map>
				<entry key="bean:name=testBean1">
					<bean class="com.example.ConsoleLoggingNotificationListener"/>
				</entry>
			</map>
		</property>
	</bean>

	<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
		<property name="name" value="TEST"/>
		<property name="age" value="100"/>
	</bean>

</beans>

在完成上述配置后,每当从目标MBean(bean:name=testBean1)广播一个JMX Notification时,通过notificationListenerMappings属性注册为监听器的ConsoleLoggingNotificationListener bean会收到通知。然后ConsoleLoggingNotificationListener bean可以根据Notification采取它认为合适的任何操作。spring-doc.cadn.net.cn

你也可以使用直接的 bean 名称作为导出的 bean 和监听器之间的链接,如下例所示:spring-doc.cadn.net.cn

<beans>

	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
		<property name="beans">
			<map>
				<entry key="bean:name=testBean1" value-ref="testBean"/>
			</map>
		</property>
		<property name="notificationListenerMappings">
			<map>
				<entry key="testBean">
					<bean class="com.example.ConsoleLoggingNotificationListener"/>
				</entry>
			</map>
		</property>
	</bean>

	<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
		<property name="name" value="TEST"/>
		<property name="age" value="100"/>
	</bean>

</beans>

如果您希望为包含 NotificationListener 所导出的所有 bean 注册一个单独的 MBeanExporter 实例,可以使用特殊的通配符(*)作为 notificationListenerMappings 属性映射中的键,如下所示:spring-doc.cadn.net.cn

<property name="notificationListenerMappings">
	<map>
		<entry key="*">
			<bean class="com.example.ConsoleLoggingNotificationListener"/>
		</entry>
	</map>
</property>

如果您需要执行相反的操作(即,将多个不同的监听器注册到一个MBean上),则必须使用notificationListeners列表属性(优先于notificationListenerMappings属性)。这次,我们不是为单个MBean配置一个NotificationListener,而是配置NotificationListenerBean个实例。一个NotificationListenerBean封装了一个NotificationListener以及它要注册到的ObjectName(或ObjectNames)的MBeanServerNotificationListenerBean还封装了其他一些属性,例如NotificationFilter和任意的handback对象,该对象可以在高级JMX通知场景中使用。spring-doc.cadn.net.cn

使用 NotificationListenerBean 个实例的配置与之前展示的差别不大,如下例所示:spring-doc.cadn.net.cn

<beans>

	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
		<property name="beans">
			<map>
				<entry key="bean:name=testBean1" value-ref="testBean"/>
			</map>
		</property>
		<property name="notificationListeners">
			<list>
				<bean class="org.springframework.jmx.export.NotificationListenerBean">
					<constructor-arg>
						<bean class="com.example.ConsoleLoggingNotificationListener"/>
					</constructor-arg>
					<property name="mappedObjectNames">
						<list>
							<value>bean:name=testBean1</value>
						</list>
					</property>
				</bean>
			</list>
		</property>
	</bean>

	<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
		<property name="name" value="TEST"/>
		<property name="age" value="100"/>
	</bean>

</beans>

前面的示例等同于第一个通知示例。假设我们希望在每次引发Notification时都获得一个回调对象,并且希望通过提供NotificationFilter来过滤掉多余的Notifications。下面的示例实现了这些目标:spring-doc.cadn.net.cn

<beans>

	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
		<property name="beans">
			<map>
				<entry key="bean:name=testBean1" value-ref="testBean1"/>
				<entry key="bean:name=testBean2" value-ref="testBean2"/>
			</map>
		</property>
		<property name="notificationListeners">
			<list>
				<bean class="org.springframework.jmx.export.NotificationListenerBean">
					<constructor-arg ref="customerNotificationListener"/>
					<property name="mappedObjectNames">
						<list>
							<!-- handles notifications from two distinct MBeans -->
							<value>bean:name=testBean1</value>
							<value>bean:name=testBean2</value>
						</list>
					</property>
					<property name="handback">
						<bean class="java.lang.String">
							<constructor-arg value="This could be anything..."/>
						</bean>
					</property>
					<property name="notificationFilter" ref="customerNotificationListener"/>
				</bean>
			</list>
		</property>
	</bean>

	<!-- implements both the NotificationListener and NotificationFilter interfaces -->
	<bean id="customerNotificationListener" class="com.example.ConsoleLoggingNotificationListener"/>

	<bean id="testBean1" class="org.springframework.jmx.JmxTestBean">
		<property name="name" value="TEST"/>
		<property name="age" value="100"/>
	</bean>

	<bean id="testBean2" class="org.springframework.jmx.JmxTestBean">
		<property name="name" value="ANOTHER TEST"/>
		<property name="age" value="200"/>
	</bean>

</beans>

(有关handback对象的完整讨论,以及实际上有关NotificationFilter的讨论,请参阅JMX规范(1.2)中名为“JMX通知模型”的章节。)spring-doc.cadn.net.cn

发布通知

Spring 不仅支持注册以接收 Notifications,还支持发布 Notificationsspring-doc.cadn.net.cn

本节仅适用于通过 MBeanExporter 暴露为 MBeans 的 Spring 管理的 Bean。任何现有的用户定义的 MBeans 应该使用标准的 JMX API 进行通知发布。

Spring的JMX通知发布支持中的关键接口是 NotificationPublisher接口(在 org.springframework.jmx.export.notification包中定义)。任何要通过 MBeanExporter实例导出为MBean的bean都可以实现相关的 NotificationPublisherAware接口,以获得对 NotificationPublisher 实例的访问权限。该 NotificationPublisherAware接口通过一个简单的setter方法向实现该接口的bean提供一个 NotificationPublisher的实例,该bean随后可以发布 Notificationsspring-doc.cadn.net.cn

如 javadoc 中所述, NotificationPublisher 接口,通过 NotificationPublisher 机制发布事件的托管 Bean 不负责通知监听器的状态管理。 Spring 的 JMX 支持会处理所有 JMX 基础设施问题。 作为应用程序开发人员,您需要实现 NotificationPublisherAware 接口并通过使用提供的 NotificationPublisher 实例开始发布事件。请注意, NotificationPublisher 是在托管 Bean 注册到 MBeanServer 之后设置的。spring-doc.cadn.net.cn

使用 NotificationPublisher 实例非常简单。您需要创建一个 JMX Notification 实例(或适当的 Notification 子类的实例), 将与要发布的事件相关的数据填充到通知中, 然后在 sendNotification(Notification) 上调用 NotificationPublisher 实例,并传入 Notificationspring-doc.cadn.net.cn

在下面的示例中,导出的 JmxTestBean 实例在每次调用 add(int, int) 操作时发布一个 NotificationEventspring-doc.cadn.net.cn

package org.springframework.jmx;

import org.springframework.jmx.export.notification.NotificationPublisherAware;
import org.springframework.jmx.export.notification.NotificationPublisher;
import javax.management.Notification;

public class JmxTestBean implements IJmxTestBean, NotificationPublisherAware {

	private String name;
	private int age;
	private boolean isSuperman;
	private NotificationPublisher publisher;

	// other getters and setters omitted for clarity

	public int add(int x, int y) {
		int answer = x + y;
		this.publisher.sendNotification(new Notification("add", this, 0));
		return answer;
	}

	public void dontExposeMe() {
		throw new RuntimeException();
	}

	public void setNotificationPublisher(NotificationPublisher notificationPublisher) {
		this.publisher = notificationPublisher;
	}

}

NotificationPublisher 接口以及使其正常工作的机制是 Spring 的 JMX 支持中较为出色的功能之一。然而,这也会带来与 Spring 和 JMX 耦合的代价。一如既往,这里的建议是保持务实。如果你需要 NotificationPublisher 提供的功能,并且可以接受与 Spring 和 JMX 的耦合,那么就可以这么做。spring-doc.cadn.net.cn