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

将您的Bean导出到JMX

Spring 的 JMX 框架中的核心类是 MBeanExporter。该类负责将您的 Spring beans 注册到 JMX MBeanServer 中。 例如,考虑以下类:spring-doc.cadn.net.cn

package org.springframework.jmx;

public class JmxTestBean implements IJmxTestBean {

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

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

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

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

要将该bean的属性和方法作为MBean的属性和操作公开,您可以在配置文件中配置一个MBeanExporter类的实例,并传入该bean,如下例所示:spring-doc.cadn.net.cn

<beans>
	<!-- this bean must not be lazily initialized if the exporting is to happen -->
	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
		<property name="beans">
			<map>
				<entry key="bean:name=testBean1" value-ref="testBean"/>
			</map>
		</property>
	</bean>
	<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
		<property name="name" value="TEST"/>
		<property name="age" value="100"/>
	</bean>
</beans>

前面配置片段中的相关bean定义是 exporter bean。 beans 属性告诉 MBeanExporter 哪些你的bean必须被导出到JMX MBeanServer。在默认配置中,beans Map 中每个条目的键被用作由相应条目值引用的bean的 ObjectName。你可以更改此行为,如 控制您的Bean的 ObjectName 实例 中所述。spring-doc.cadn.net.cn

通过此配置,testBean bean 作为 MBean 在 ObjectName bean:name=testBean1 下公开。默认情况下,该 bean 的所有 public 属性都会作为属性公开,所有 public 方法(除从 Object 类继承的方法外)都会作为操作公开。spring-doc.cadn.net.cn

MBeanExporter 是一个 Lifecycle bean(参见 启动和关闭回调)。默认情况下,MBeans 会在应用程序生命周期尽可能晚的时候导出。您可以配置 phase 来确定导出的时间点,或者通过设置 autoStartup 标志来禁用自动注册。

创建MBeanServer

在上一节中显示的配置假设应用程序正在一个已经运行了一个(且仅有一个)MBeanServer的环境中运行。在这种情况下,Spring会尝试找到正在运行的MBeanServer,并将您的bean注册到该服务器(如果有的话)。当您的应用程序在具有自己MBeanServer的容器(如Tomcat或IBM WebSphere)中运行时,这种行为很有用。spring-doc.cadn.net.cn

然而,在独立环境中或在不提供MBeanServer的容器中运行时,这种方法没有用处。为了解决这个问题,可以通过将org.springframework.jmx.support.MBeanServerFactoryBean类的实例添加到配置中,以声明方式创建一个MBeanServer实例。 您还可以通过将MBeanExporter实例的server属性设置为由MBeanServerFactoryBean返回的MBeanServer值,来确保使用特定的MBeanServer,如下例所示:spring-doc.cadn.net.cn

<beans>

	<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"/>

	<!--
	this bean needs to be eagerly pre-instantiated in order for the exporting to occur;
	this means that it must not be marked as lazily initialized
	-->
	<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="server" ref="mbeanServer"/>
	</bean>

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

</beans>

在前面的示例中,通过 MBeanServer 创建了一个 MBeanServerFactoryBean 的实例,并通过 server 属性提供给 MBeanExporter。当你提供自己的 MBeanServer 实例时,MBeanExporter 不会尝试查找正在运行的 MBeanServer,而是使用提供的 MBeanServer 实例。为了正确工作,你必须在类路径上有 JMX 实现。spring-doc.cadn.net.cn

重用现有的 MBeanServer

如果没有指定服务器,MBeanExporter 会尝试自动检测正在运行的MBeanServer。这在大多数环境中有效,其中只使用了一个MBeanServer实例。然而,当存在多个实例时,导出器可能会选择错误的服务器。在这种情况下,您应该使用MBeanServer agentId来指示要使用的实例,如下例所示:spring-doc.cadn.net.cn

<beans>
	<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
		<!-- indicate to first look for a server -->
		<property name="locateExistingServerIfPossible" value="true"/>
		<!-- search for the MBeanServer instance with the given agentId -->
		<property name="agentId" value="MBeanServer_instance_agentId>"/>
	</bean>
	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
		<property name="server" ref="mbeanServer"/>
		...
	</bean>
</beans>

对于平台或情况,其中现有的 MBeanServer 具有通过查找方法检索的动态(或未知)agentId,应使用 工厂方法,如下例所示:spring-doc.cadn.net.cn

<beans>
	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
		<property name="server">
			<!-- Custom MBeanServerLocator -->
			<bean class="platform.package.MBeanServerLocator" factory-method="locateMBeanServer"/>
		</property>
	</bean>

	<!-- other beans here -->

</beans>

延迟初始化的MBean

如果使用一个配置了 MBeanExporter 的 Bean,该 Bean 也配置为延迟初始化,那么 MBeanExporter 不会破坏此契约,并避免实例化该 Bean。相反,它会将代理注册到 MBeanServer,并推迟从容器中获取 Bean 直到第一次调用代理时。spring-doc.cadn.net.cn

这还会影响 FactoryBean 分辨率,其中 MBeanExporter 将定期对生成的对象进行内省,从而有效触发 FactoryBean.getObject()。 为避免此情况,请将相应的 bean 定义标记为 lazy-init。spring-doc.cadn.net.cn

自动注册MBeans

通过 MBeanExporter 导出的任何 bean,如果已经是有效的 MBean,则会直接注册到 MBeanServer,而无需 Spring 的进一步干预。您可以通过将 autodetect 属性设置为 true,使 MBeanExporter 自动检测 MBean,如下例所示:spring-doc.cadn.net.cn

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
	<property name="autodetect" value="true"/>
</bean>

<bean name="spring:mbean=true" class="org.springframework.jmx.export.TestDynamicMBean"/>

在前面的示例中,名为 spring:mbean=true 的 bean 已经是一个有效的 JMX MBean 并由 Spring 自动注册。默认情况下,被自动检测用于 JMX 注册的 bean 会将其 bean 名称用作 ObjectName。您可以覆盖此行为, 如 控制您的 Bean 的 ObjectName 实例 中所述。spring-doc.cadn.net.cn

控制注册行为

考虑这样一个场景,其中 Spring MBeanExporter 尝试通过使用 ObjectName bean:name=testBean1 注册一个 MBean,带有 MBeanServer。如果该相同的 ObjectName 下已经注册了一个 MBean 实例,则默认行为是失败(并抛出 InstanceAlreadyExistsException)。spring-doc.cadn.net.cn

您可以精确控制当一个 MBean 与一个 MBeanServer 注册时发生的情况。Spring 的 JMX 支持允许三种不同的注册行为,用于在注册过程中发现同一 ObjectName 下已注册了一个 MBean 时,控制注册行为。下表总结了这些注册行为:spring-doc.cadn.net.cn

表 1. 注册行为
注册行为 说明

FAIL_ON_EXISTINGspring-doc.cadn.net.cn

这是默认的注册行为。如果在相同的 ObjectName 下已经注册了一个 MBean 实例,则正在注册的 MBean 不会进行注册,并且会抛出一个 InstanceAlreadyExistsException。现有的 MBean 不受影响。spring-doc.cadn.net.cn

IGNORE_EXISTINGspring-doc.cadn.net.cn

如果在相同的 ObjectName 下已经注册了一个 MBean 实例,则不会注册正在注册的 MBean。现有的 MBean 不受影响,也不会抛出 Exception。这在多个应用程序想要在共享的 MBeanServer 中共享一个公共的 MBean 的环境中很有用。spring-doc.cadn.net.cn

REPLACE_EXISTINGspring-doc.cadn.net.cn

如果在相同的ObjectName下已经注册了一个MBean实例,则会取消注册之前注册的MBean,并用新的MBean替换它(新的MBean实际上取代了之前的实例)。spring-doc.cadn.net.cn

前面表格中的值定义在RegistrationPolicy类上。 如果您想更改默认的注册行为,需要将您的MBeanExporter定义上的registrationPolicy属性的值设置为这些值之一。spring-doc.cadn.net.cn

以下示例显示了如何从默认注册行为更改为 REPLACE_EXISTING 行为: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="registrationPolicy" value="REPLACE_EXISTING"/>
	</bean>

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

</beans>