Following various example configurations from Spring documentation as well as some forums on the Internet, my application context file looks like:
<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'm running this without any container and on plain JVM. I'm able to connect to my process via JConsole but the MBean doesn't show up. However registering the bean programmatically exposes it successfully.
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
DH dh = new DH(0);
mbeanServer.registerMBean(dh, new ObjectName("bean:name=dH1"));
I've tried playing with the Spring configuration without success. I think the bean is not registering to the already running MBean server that was accessible from ManagementFactory.getPlatformMBeanServer(). Any ideas on the issue?
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 the MBeanExporter what to manage:
If a bean implements one of the JMX management interfaces, MBeanExporter can simply register the MBean with the server through its autodetection process.
If a bean does not implement one of the JMX management interfaces, MBeanExporter will create the management information using the supplied MBeanInfoAssembler.
Assuming your abc.def.ghi.DH
class does not implement any JMX interface, try defining your 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 the OpenJDK 7, update 2, build 21 DefaultMBeanServerInterceptor.java
source, line 898 creates a DynamicMBean
for regular objects:
DynamicMBean mbean = Introspector.makeDynamicMBean(object);
I haven't debugged it, but I bet mbeanServer.registerMBean(dh, new ObjectName("bean:name=dH1"))
eventually calls DefaultMBeanServerInterceptor.registerObject()
, which creates a DynamicMBean
for you and properly registers your standard JavaBean
properties' setters and getters.
Here are some test files that work using Spring Framework 3.0.5 and Oracle HotSpot Java 1.6.0_24. After setting your CLASSPATH
environment variable, just run javac *.java
and java Main
and use VisualVM (or 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) {}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With