将您的Bean导出到JMX
Spring JMX框架中的核心类是MBeanExporter
。此类负责获取您的Spring Bean并将它们注册到JMX MBeanServer
。例如,考虑以下类
-
Java
-
Kotlin
public class JmxTestBean implements IJmxTestBean {
private String name;
private int age;
@Override
public int getAge() {
return age;
}
@Override
public void setAge(int age) {
this.age = age;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public int add(int x, int y) {
return x + y;
}
@Override
public void dontExposeMe() {
throw new RuntimeException();
}
}
class JmxTestBean : IJmxTestBean {
private lateinit var name: String
private var age = 0
override fun getAge(): Int {
return age
}
override fun setAge(age: Int) {
this.age = age
}
override fun setName(name: String) {
this.name = name
}
override fun getName(): String {
return name
}
override fun add(x: Int, y: Int): Int {
return x + y
}
override fun dontExposeMe() {
throw RuntimeException()
}
}
要将此Bean的属性和方法作为MBean的属性和操作公开,您可以在配置文件中配置MBeanExporter
类的实例,并将Bean作为参数传入,如下例所示:
-
Java
-
Kotlin
-
XML
@Configuration
public class JmxConfiguration {
@Bean
MBeanExporter exporter(JmxTestBean testBean) {
MBeanExporter exporter = new MBeanExporter();
exporter.setBeans(Map.of("bean:name=testBean1", testBean));
return exporter;
}
@Bean
JmxTestBean testBean() {
JmxTestBean testBean = new JmxTestBean();
testBean.setName("TEST");
testBean.setAge(100);
return testBean;
}
}
@Configuration
class JmxConfiguration {
@Bean
fun exporter(testBean: JmxTestBean) = MBeanExporter().apply {
setBeans(mapOf("bean:name=testBean1" to testBean))
}
@Bean
fun testBean() = JmxTestBean().apply {
name = "TEST"
age = 100
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- this bean must not be lazily initialized if the exporting is to happen -->
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
</bean>
<bean id="testBean" class="org.example.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
实例中所述。
通过此配置,testBean
Bean作为ObjectName
bean:name=testBean1
下的MBean公开。默认情况下,Bean的所有public
属性都公开为属性,所有public
方法(继承自Object
类的方法除外)都公开为操作。
MBeanExporter 是一个Lifecycle Bean(参见启动和关闭回调)。默认情况下,MBean在应用程序生命周期的尽可能晚的时间导出。您可以配置导出发生的phase ,或者通过设置autoStartup 标志来禁用自动注册。 |
创建MBeanServer
上一节中显示的配置假定应用程序在已运行一个(且只有一个)MBeanServer
的环境中运行。在这种情况下,Spring尝试找到正在运行的MBeanServer
并将您的Bean注册到该服务器(如果有)。当您的应用程序在具有其自身MBeanServer
的容器(例如Tomcat或IBM WebSphere)中运行时,此行为非常有用。
但是,这种方法在独立环境中或在不提供MBeanServer
的容器中运行时无效。为了解决这个问题,您可以通过向配置中添加org.springframework.jmx.support.MBeanServerFactoryBean
类的实例来声明性地创建一个MBeanServer
实例。您还可以通过将MBeanExporter
实例的server
属性的值设置为MBeanServerFactoryBean
返回的MBeanServer
值来确保使用特定的MBeanServer
,如下例所示:
<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实现。
重用现有的MBeanServer
如果没有指定服务器,MBeanExporter
将尝试自动检测正在运行的MBeanServer
。这在大多数环境中都能正常工作,因为只使用一个MBeanServer
实例。但是,当存在多个实例时,导出器可能会选择错误的服务器。在这种情况下,您应该使用MBeanServer
agentId
来指示要使用的实例,如下例所示:
<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
(通过查找方法检索)的平台或情况,您应该使用factory-method,如下例所示:
<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,则MBeanExporter
不会破坏此约定,并避免实例化Bean。相反,它使用代理向MBeanServer
注册,并将从容器中获取Bean推迟到对代理的第一次调用发生。
这也影响FactoryBean
的解析,其中MBeanExporter
将定期内省生成的objects,从而有效地触发FactoryBean.getObject()
。为了避免这种情况,请将相应的Bean定义标记为lazy-init。
MBean的自动注册
通过MBeanExporter
导出的任何已经是有效MBean的Bean都将按原样注册到MBeanServer
,而无需Spring进一步干预。您可以通过将autodetect
属性设置为true
来使MBean被MBeanExporter
自动检测,如下例所示:
<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 MBeanExporter
尝试使用ObjectName
bean:name=testBean1
将MBean
注册到MBeanServer
的情况。如果已在同一ObjectName
下注册了MBean
实例,则默认行为是失败(并抛出InstanceAlreadyExistsException
)。
您可以精确控制将MBean
注册到MBeanServer
时发生的情况。Spring的JMX支持允许使用三种不同的注册行为来控制当注册过程发现已在同一ObjectName
下注册了MBean
时的注册行为。下表总结了这些注册行为
注册行为 | 说明 |
---|---|
|
这是默认的注册行为。如果已在同一 |
|
如果已在同一 |
|
如果已在同一 |
上表中的值在RegistrationPolicy
类中定义为枚举。如果要更改默认注册行为,需要将MBeanExporter
定义中的registrationPolicy
属性的值设置为这些值之一。
以下示例显示如何将默认注册行为更改为REPLACE_EXISTING
行为。
<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>