spring的JMX支持使你可以将你的Spring应用程序集成到JMX框架中。
特别是,Spring的JMX支持提供了四个核心功能:
- 任何Spring bean,作为一个JMX MBean,的自动注册功能
- 提供了一个灵活的机制控制你的beans管理接口
- 本地和远程MBean资源的简单代理
- The declarative exposure of MBeans over remote, JSR-160 connectors
这些功能设计成无需将你的应用程序组件结合到Spring或者JMX的接口和类上。事实上,对于大多数应用程序部分,不需要关注Spring或JMX,而充分利用Spring的JMX功能。
24.2 暴露beans给JMX
Spring的JMX框架的核心类是MBeanExporter
。这个类用于获取你的Spring beans并以一个JMXMBeanServer
注册它们。例如,考虑下面的例子:
- 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中传递。
- <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
,并涉及到对应的记录值。
在这个配置中,testBean
在ObjectName
bean:name=testBean1以一个MBean暴露。默认地,这个bean的所有属性以元素暴露并且这个bean的所有方法(除了那些从Object类中继承的)以操作暴露。
注意
MBeanExporter
是个有声明周期的bean,并且在应用程序生命周期期间,默认地,竟可能晚的输出MBeans。
24.2.1 创建一个MBeanServer
上述的配置假设应用程序运行在一个环境中,其有且只有一个MBeanServer在运行。在这种情况下,Spring将尝试定位运行的MBeanServer并且在那个服务器上注册你的beans(如果有服务器的话)。当应用程序运行在容器内部时,这个行为是很有用的,比如Tomcat或者IBM的WebSphere都有自己的MBeanServer。
然而,这种方式在一个独立的环境中是无用的,或者当运行在一个容器内部,是不提供MBeanServer。为寻址这个,你可以分开创建一个MBeanServer,通过添加org.springframework.jmx.support.MBeanServerFactoryBean的一个实例到你的配置中。你也可以确保一个指定的MBeanServer,通过MBeanExporter的server属性的值设置为MBeanServer的值,其由MBeanServerFactoryBean返回。例如:
- <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>
这是一个由MBeanServerFactoryBean创建的MBeanServer的实例并借助server属性传递给MBeanExporter。当你传递你自己的MBeanServer实例时,MBeanExporter将不会尝试着定位一个运行的MBeanServer并将使用提供的MBeanServer实例。为了使这个正确的工作,你必须在你的系统路径上有一个JMX实现。
24.2.2 重用已经存在的MBeanServer
如果没有指定服务器,MBeanExporter尝试着自动分发一个运行的MBeanServer。这在只有一个MBeanServer实例使用的环境中有效,然而当多个实例存在的时候,exporter可能选择错误的服务器。在这样的情况下,使用者应该使用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,其将通过lookup方法重新获取,应该使用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>
24.2.3 Lazy-initialized MBeans
如果你为MBeanExporter配置了一个bean,那也需要配置延迟初始化,之后MBeanExporter将不会打破这个约束并避免初始化这个bean。另外,使用MBeanServer注册了一个代理,并推迟从容器中获取这个bean,直到这个代理进行了第一次调用。
24.2.4 自动注册MBeans
任何通过MBeanExporter输出和已经有效的MBeans,注册为MBeanServer而无需Spring更多的参与。MBeans可以通过设置autodetect为true,通过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注册器自动分发的beans将它们的bean 名字作为ObjectName。这个行为可以重写的。
24.2.5 控制注册器行为
考虑这个场景,一个Spring的MBeanExporter尝试使用ObjectName 'bean:name=testBean1'向一个MBeanServer注册一个MBean。如果一个MBean实例已经注册了相同的ObjectName,默认行为就是失败(并抛出异常InstanceAlreadyExistsException)。
当Mbean注册到一个MBeanServer时,是可以控制所发生的行为的。Spring的XML支持允许三个不同的注册行为来控制这些,当注册动作发现一个Mbean已经注册了同样的ObjectName时;这些注册行为总结如下:
注册行为表:
注册动作 解释
REGISTRATION_FAIL_ON_EXISTING 这是默认的注册行为。如果一个Mbean实例注册了相同的ObjectName,已经注册的Mbean将不会再注册,并抛出异常InstanceAlreadyExistsException。已经存在的Mbean不受影响
REGISTRATION_IGNORE_EXISTING 如果一个Mbean实例注册了相同的ObjectName,将要注册的Mbean将不被注册。已经存在的Mbean不受影响,并不抛出异常。这在多应用程序中在一个共享的MBeanServer中共享一个通用的MBean是很有用的。
REGISTRATION_REPLACE_EXISTING 如果一个Mbean实例注册了相同的ObjectName,预先注册已经存在的MBean将不被注册并且新的Mbean将注册在前者的位置上(新的Mbean替代之前的实例)
上述值以常量值定义在MBeanRegistrationSupport类中(MBeanExporter源于这个父类)。如果你想改变这个默认的注册行为,你仅仅需要在你的MBeanExporter定义上设置registrationBehaviorName属性的值为那些值中的一个。
下面的例子演示了如何改变默认的注册行为为REGISTRATION_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="registrationBehaviorName" value="REGISTRATION_REPLACE_EXISTING"/>
- </bean>
- <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
- <property name="name" value="TEST"/>
- <property name="age" value="100"/>
- </bean>
- </beans>