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

将您的 Bean 导出到 JMX

Spring JMX 框架中的核心类是 MBeanExporter。该类负责将你的 Spring Bean 注册到 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 的形式暴露出来,其 ObjectNamebean:name=testBean1。默认情况下,该 bean 的所有 public 属性都会作为属性(attributes)暴露出来,所有 public 方法(从 Object 类继承的方法除外)都会作为操作(operations)暴露出来。spring-doc.cadn.net.cn

MBeanExporter 是一个 Lifecycle Bean(参见启动和关闭回调)。 默认情况下,MBean 会在应用程序生命周期中尽可能晚的阶段被导出。你可以配置导出发生的 phase(阶段),或者通过设置 autoStartup 标志来禁用自动注册。

创建 MBeanServer

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

然而,这种方法在独立环境(standalone environment)中或在未提供 MBeanServer 的容器中运行时毫无用处。为了解决这个问题,您可以在配置中添加一个 MBeanServer 类的实例,以声明式的方式创建一个 org.springframework.jmx.support.MBeanServerFactoryBean 实例。 您还可以通过将 MBeanServer 实例的 MBeanExporter 属性设置为由 server 返回的 MBeanServer 值,来确保使用特定的 MBeanServerFactoryBean,如下例所示: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 创建,并通过 MBeanExporter 属性提供给 server。当您提供自己的 MBeanServer 实例时,MBeanExporter 不会尝试查找正在运行的 MBeanServer,而是使用所提供的 MBeanServer 实例。要使此功能正常工作,您的类路径中必须包含一个 JMX 实现。spring-doc.cadn.net.cn

复用现有的MBeanServer

如果没有指定服务器,MBeanExporter 会尝试自动检测一个正在运行的 MBeanServer。这在大多数环境中都能正常工作,因为通常只使用一个 MBeanServer 实例。 然而,当存在多个实例时,导出器可能会选择错误的服务器。 在这种情况下,您应使用 MBeanServeragentId 来指明应使用哪个实例,如下例所示: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 的平台或场景,该 xref page 需通过查找方法获取,此时您应使用 factory-method, 如下例所示: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>

延迟初始化的 MBeans

如果你配置了一个使用 MBeanExporter 的 bean,并且该 bean 同时被配置为延迟初始化,那么 MBeanExporter 不会破坏这一约定,也不会提前实例化该 bean。相反,它会向 MBeanServer 注册一个代理,并推迟从容器中获取该 bean,直到首次通过该代理调用发生时才进行。spring-doc.cadn.net.cn

这也会影响 FactoryBean 的解析,因为 MBeanExporter 会定期对所生成的对象进行内省,实际上会触发 FactoryBean.getObject()。 为避免这种情况,请将相应的 bean 定义标记为 lazy-init(懒加载)。spring-doc.cadn.net.cn

MBean 的自动注册

任何通过 MBeanExporter 导出且已经是有效 MBean 的 Bean, 都会直接注册到 MBeanServer 中,无需 Spring 进行额外干预。 你可以通过将 MBeanExporter 属性设置为 autodetect, 让 true 自动检测 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 尝试使用 MBean MBeanServerObjectName 注册一个 bean:name=testBean1。如果已有另一个 MBean 实例注册在相同的 ObjectName 下,默认行为是失败(并抛出 InstanceAlreadyExistsException)。spring-doc.cadn.net.cn

你可以精确控制当一个 MBeanMBeanServer 注册时所发生的行为。Spring 的 JMX 支持三种不同的注册行为,用于在注册过程中发现已有相同 MBeanObjectName 时控制注册行为。下表总结了这些注册行为:spring-doc.cadn.net.cn

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

FAIL_ON_EXISTINGspring-doc.cadn.net.cn

这是默认的注册行为。如果一个 MBean 实例已经使用相同的 ObjectName 注册过了,那么正在尝试注册的 MBean 将不会被注册,并会抛出一个 InstanceAlreadyExistsException 异常。原有的 MBean 不受影响。spring-doc.cadn.net.cn

IGNORE_EXISTINGspring-doc.cadn.net.cn

如果已有一个 MBean 实例在相同的 ObjectName 下注册, 则正在注册的 MBean 将不会被注册。现有的 MBean 不受影响, 也不会抛出任何 Exception。这在多个应用程序希望在共享的 MBean 中 共享同一个 MBeanServer 的场景下非常有用。spring-doc.cadn.net.cn

REPLACE_EXISTINGspring-doc.cadn.net.cn

如果一个 MBean 实例已经使用相同的 ObjectName 注册过, 则先前注册的现有 MBean 将被注销,并用新的 MBean 取而代之(新的 MBean 实质上替换了之前的实例)。spring-doc.cadn.net.cn

上表中的值在 RegistrationPolicy 类中定义为枚举。 如果你想更改默认的注册行为,需要将 registrationPolicy 定义中的 MBeanExporter 属性值设置为这些枚举值之一。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>