Регистрация JMX MBean с использованием Spring на автономной JVM - PullRequest
8 голосов
/ 06 февраля 2012

Следуя различным примерным конфигурациям из документации Spring, а также некоторых форумов в Интернете, мой файл контекста приложения выглядит следующим образом:

<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 безуспешно.Я думаю, что бин не регистрируется на уже работающем сервере MBean, который был доступен из ManagementFactory.getPlatformMBeanServer ().Есть идеи по этому вопросу?

Ответы [ 2 ]

12 голосов
/ 10 февраля 2012

В дополнение к определению MBeanServerFactory bean (как Николас отмечен в их ответе ) с использованием ...

<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 *.java и java Main и используйте VisualVM (или подобное приложение), чтобы подключиться к работающему приложению java и увидеть зарегистрированные MBeans.

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) {}
    }
}
2 голосов
/ 06 февраля 2012

Проблема связана с MBeanServerFactoryBean.

Из javadoc :

По умолчанию MBeanServerFactoryBean всегда создает новый MBeanServer, даже если он уже существует.Бег.Чтобы MBeanServerFactoryBean пытался сначала найти работающий MBeanServer, задайте для свойства «locateExistingServerIfPossible» значение «true».

Попробуйте эту конфигурацию:

<bean 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" 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>
...