在独立的JVM上使用Spring进行JMX MBean注册

时间:2012-02-06 16:57:33

标签: java spring jvm jmx

根据Spring文档以及Internet上的一些论坛的各种示例配置,我的应用程序上下文文件如下所示:

<beans>
    <bean id="dH" class="abc.def.ghi.DH">
        <constructor-arg>
            <value>0</value>
        </constructor-arg>
        <property name="num" value="100"/>
    </bean>
    <bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
            <property name="beans">
              <map>
                    <entry key="bean:name=dH1" value-ref="dH"/>
              </map>
            </property>
    </bean>
    <bean class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
</beans>

我在没有任何容器和普通JVM的情况下运行它。我可以通过JConsole连接到我的进程,但MBean没有出现。但是,以编程方式注册bean会成功公开它。

MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
DH dh = new DH(0);
mbeanServer.registerMBean(dh, new ObjectName("bean:name=dH1"));

我尝试过使用Spring配置但没有成功。我认为bean没有注册到可以从ManagementFactory.getPlatformMBeanServer()访问的已经运行的MBean服务器。 关于这个问题的任何想法?

2 个答案:

答案 0 :(得分:12)

除了使用...定义MBeanServerFactory bean(在Nicholas中注明为answer)之外...

<bean class="org.springframework.jmx.support.MBeanServerFactoryBean">
    <property name="locateExistingServerIfPossible" value="true" />
</bean>

...您需要告诉MBeanExporter要管理的内容:

  

如果bean实现了一个JMX管理接口,MBeanExporter可以通过其自动检测过程向服务器注册MBean。

     

如果bean没有实现其中一个JMX管理接口,MBeanExporter将使用提供的MBeanInfoAssembler创建管理信息。

假设您的abc.def.ghi.DH类未实现任何JMX界面,请尝试将MBeanExporter定义为:

<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
    <property name="assembler">
        <bean
            class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler"
        >
            <property name="managedMethods">
                <list>
                    <value>getNum</value>
                </list>
            </property>
        </bean>
    </property>
    <property name="beans">
        <map>
            <entry key="bean:name=dH1" value-ref="dH"/>
        </map>
    </property>
</bean>

查看OpenJDK 7,更新2,构建21 DefaultMBeanServerInterceptor.java源,第898行为常规对象创建DynamicMBean

DynamicMBean mbean = Introspector.makeDynamicMBean(object);

我没有调试它,但我打赌mbeanServer.registerMBean(dh, new ObjectName("bean:name=dH1"))最终会调用DefaultMBeanServerInterceptor.registerObject(),这会为您创建DynamicMBean并正确注册您的标准JavaBean属性'设置器和吸气剂。


以下是一些使用Spring Framework 3.0.5和Oracle HotSpot Java 1.6.0_24的测试文件。设置CLASSPATH环境变量后,只需运行javac *.javajava Main并使用VisualVM(或类似的应用程序)连接到正在运行的java应用程序,以查看已注册的MBean。

<强> ac.xml

<?xml version="1.0" encoding="UTF-8"?>
<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
        http://www.springframework.org/schema/beans/spring-beans.xsd"
    default-lazy-init="true"
>
    <bean id="test" class="Test" />
    <bean class="org.springframework.jmx.support.MBeanServerFactoryBean">
        <property name="locateExistingServerIfPossible" value="true" />
    </bean>
    <bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
        <property name="assembler">
            <bean
                class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler"
            >
                <property name="managedMethods">
                    <list>
                        <value>getVal</value>
                        <value>setVal</value>
                    </list>
                </property>
            </bean>
        </property>
        <property name="beans">
            <map>
                <entry key="bean:name=Test" value-ref="test"/>
            </map>
        </property>
    </bean>
</beans>

<强> Test.java

public class Test {
    private String val = "";
    public String getVal() {
        return val;
    }
    public void setVal(String v) {
        val = v;
    }
}

<强> Main.java

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
    public static void main(final String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("ac.xml");
        try {
            Thread.sleep(1000 * 60 * 5);
        } catch (final Throwable t) {}
    }
}

答案 1 :(得分:2)

问题在于MBeanServerFactoryBean。

来自javadoc

  

默认情况下,MBeanServerFactoryBean将始终创建一个新的   MBeanServer即使已经运行了。拥有   MBeanServerFactoryBean首先尝试查找正在运行的MBeanServer,   将“locateExistingServerIfPossible”属性的值设置为   “真”。

试试这个配置:

<bean class="org.springframework.jmx.support.MBeanServerFactoryBean">
    <property name="locateExistingServerIfPossible" value="true" />
</bean>

<强> ============================================ =====

尝试在导出器bean中指定MBeanServer:

<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
    <property name="beans">
        <map>
                <entry key="bean:name=dH1" value-ref="dH" />
            </map>
        </property>
        <property name="server" ref="MBeanServer" />
</bean>
<bean id="MBeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
    <property name="locateExistingServerIfPossible" value="true" />
</bean>

<强> ============================================ ============================

好的,让我们采用强力方法直接获取平台MBeanServer:

<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
    <property name="beans">
        <map>
                <entry key="bean:name=dH1" value-ref="dH" />
            </map>
        </property>
        <property name="server">
            <bean id="MBeanServer" class="java.lang.management.ManagementFactory" factory-method="getPlatformMBeanServer"/>
        </property>
</bean>