Register JMX MBean using Spring on a standalone JVM

Following various configuration examples from the Spring documentation, as well as some forums on the Internet, my application context file looks like this:

<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> 

I run this without any container and on a simple JVM. I can connect to my process through JConsole, but the MBean is not displayed. However, registering a bean programmatically provides it successfully.

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

I tried playing with Spring configuration without success. I think that the bean is not registered on the already running MBean server, accessible from ManagementFactory.getPlatformMBeanServer (). Any ideas on this issue?

+8
java spring jvm jmx
source share
2 answers

In addition to defining an MBeanServerFactory bean (as Nicholas noted in their answer ), using ...

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

... you need to tell MBeanExporter what you need to manage:

If the bean implements one of the JMX management interfaces, the MBeanExporter can simply register the MBean with the server through its automatic detection process.

If the bean does not implement one of the JMX management interfaces, MBeanExporter will generate control information using the provided MBeanInfoAssembler.

Assuming your class abc.def.ghi.DH does not implement any JMX interface, try defining MBeanExporter as:

 <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> 

Looking at OpenJDK 7, update 2, build the 21 DefaultMBeanServerInterceptor.java source, line 898 creates a DynamicMBean for ordinary objects:

 DynamicMBean mbean = Introspector.makeDynamicMBean(object); 

I did not debug it, but I put that mbeanServer.registerMBean(dh, new ObjectName("bean:name=dH1")) ultimately calls DefaultMBeanServerInterceptor.registerObject() , which creates for you DynamicMBean and correctly registers your standard setters and recipients of JavaBean properties.


Here are some test files that work using Spring Framework 3.0.5 and Oracle HotSpot Java 1.6.0_24. After setting the CLASSPATH environment variable, just run javac *.java and java Main and use VisualVM (or a similar application) to connect to the running java application to see the registered 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) {} } } 
+11
source share

The problem is related to MBeanServerFactoryBean.

From javadoc :

By default, MBeanServerFactoryBean will always create a new MBeanServer, even if it is already running. In order for MBeanServerFactoryBean to first try to find the running MBeanServer, set the value of the locateExistingServerIfPossible property. "True".

Try this configuration:

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

===================================================

Try specifying MBeanServer in the bean exporter:

 <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> 

============================================= ====== ========================

Ok, take a brute force approach and immediately get the MBeanServer platform:

 <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> 
+2
source share

All Articles