diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java index 1337250856..75c9889fa0 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java @@ -13,6 +13,8 @@ package org.springframework.integration.jmx.config; +import java.util.UUID; + import javax.management.MBeanServerFactory; import org.w3c.dom.Element; @@ -26,12 +28,14 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; +import org.springframework.integration.monitor.IntegrationMBeanExporter; import org.springframework.util.StringUtils; /** * Parser for the 'mbean-export' element of the integration JMX namespace. * * @author Mark Fisher + * @author Gary Russell * @since 2.0 */ public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser { @@ -46,7 +50,7 @@ public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser { @Override protected String getBeanClassName(Element element) { - return "org.springframework.integration.monitor.IntegrationMBeanExporter"; + return IntegrationMBeanExporter.class.getName(); } @Override @@ -85,6 +89,10 @@ public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser { " (clashes with default). Please choose another bean id.", definition); } + if (id.matches(IntegrationMBeanExporter.class.getName() + "#[0-9]+")) { + // Randomize the name in case there are multiple contexts in the same JVM + id += "#" + UUID.randomUUID(); + } return id; } diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java index e9d9e079f4..f2621dda66 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java @@ -90,6 +90,7 @@ import org.springframework.util.ReflectionUtils; * @author Dave Syer * @author Helena Edelson * @author Oleg Zhurakousky + * @author Gary Russell */ @ManagedResource public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostProcessor, BeanFactoryAware, @@ -516,7 +517,8 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP // Expose the raw bean if it is managed MessageChannel bean = monitor.getMessageChannel(); if (assembler.includeBean(bean.getClass(), monitor.getName())) { - registerBeanInstance(bean, monitor.getName()); + registerBeanInstance(bean, + this.getMonitoredIntegrationObjectBeanKey(bean, name)); } } } @@ -539,7 +541,8 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP // Expose the raw bean if it is managed MessageHandler bean = source.getMessageHandler(); if (assembler.includeBean(bean.getClass(), source.getName())) { - registerBeanInstance(bean, monitor.getName()); + registerBeanInstance(bean, + this.getMonitoredIntegrationObjectBeanKey(bean, name)); } } } @@ -562,7 +565,8 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP // Expose the raw bean if it is managed MessageSource bean = source.getMessageSource(); if (assembler.includeBean(bean.getClass(), source.getName())) { - registerBeanInstance(bean, monitor.getName()); + registerBeanInstance(bean, + this.getMonitoredIntegrationObjectBeanKey(bean, name)); } } } @@ -688,6 +692,11 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP return String.format(domain + ":type=ManagedEndpoint,name=%s,bean=%s" + getStaticNames(), name, source); } + private String getMonitoredIntegrationObjectBeanKey(Object object, String name) { + // This ordering of keys seems to work with default settings of JConsole + return String.format(domain + ":type=" + object.getClass().getSimpleName() + ",name=%s" + getStaticNames(), name); + } + private String getStaticNames() { if (objectNameStaticProperties.isEmpty()) { return ""; diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/Int2307Tests.java b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/Int2307Tests.java index 397bc40b8c..de1a6e5b80 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/Int2307Tests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/Int2307Tests.java @@ -12,27 +12,57 @@ */ package org.springframework.integration_.mbeanexporterhelper; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; import java.util.Set; -import org.junit.Test; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectInstance; -import org.springframework.context.ApplicationContext; +import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.test.util.TestUtils; import org.springframework.jmx.export.MBeanExporter; -import static org.junit.Assert.assertTrue; - /** * @author Oleg Zhurakousky + * @author Gary Russell * */ public class Int2307Tests { @Test public void testInt2307_DefaultMBeanExporter() throws Exception{ - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("single-config.xml", this.getClass()); - context.destroy(); + new ClassPathXmlApplicationContext("single-config.xml", this.getClass()); + List servers = MBeanServerFactory.findMBeanServer(null); + assertEquals(1, servers.size()); + MBeanServer server = servers.get(0); + Set mbeans = server.queryMBeans(null, null); + int bits = 0; + int count = 0; + for (ObjectInstance mbean : mbeans) { + if (mbean.toString().startsWith("org.springframework.integration.router.RecipientListRouter[test.domain:type=RecipientListRouter,name=rlr,random=")) { + bits |= 1; + count++; + } else if (mbean.toString().startsWith("org.springframework.integration.monitor.LifecycleMessageHandlerMetrics[test.domain:type=MessageHandler,name=rlr,bean=endpoint,random=")) { + bits |= 2; + count++; + } else if (mbean.toString().startsWith("org.springframework.integration.router.HeaderValueRouter[test.domain:type=HeaderValueRouter,name=hvr,random=")) { + bits |= 4; + count++; + } else if (mbean.toString().startsWith("org.springframework.integration.monitor.LifecycleMessageHandlerMetrics[test.domain:type=MessageHandler,name=hvr,bean=endpoint,random=")) { + bits |= 8; + count++; + } + } + assertEquals(0xf, bits); + assertEquals(4, count); + + // make sure there are no duplicate MBean ObjectNames if 2 contexts loaded from same config + new ClassPathXmlApplicationContext("single-config.xml", this.getClass()); } @SuppressWarnings("unchecked") @@ -46,7 +76,6 @@ public class Int2307Tests { assertTrue(excludedBeanNames.contains("x")); assertTrue(excludedBeanNames.contains("y")); assertTrue(excludedBeanNames.contains("foo")); // non SI bean - context.destroy(); } public static class Foo{} diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config-custom-exporter.xml b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config-custom-exporter.xml index 670e34a37a..a3b926d6b3 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config-custom-exporter.xml +++ b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config-custom-exporter.xml @@ -3,15 +3,24 @@ xmlns:context="http://www.springframework.org/schema/context" xmlns:int="http://www.springframework.org/schema/integration" xmlns:int-jmx="http://www.springframework.org/schema/integration/jmx" + xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd http://www.springframework.org/schema/integration/jmx http://www.springframework.org/schema/integration/jmx/spring-integration-jmx-2.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - - + + + + #{new java.util.Random().nextInt()} + test + + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config.xml b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config.xml index fffedc1c31..4dd3005e3a 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config.xml +++ b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config.xml @@ -3,14 +3,24 @@ xmlns:context="http://www.springframework.org/schema/context" xmlns:int="http://www.springframework.org/schema/integration" xmlns:int-jmx="http://www.springframework.org/schema/integration/jmx" + xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd http://www.springframework.org/schema/integration/jmx http://www.springframework.org/schema/integration/jmx/spring-integration-jmx-2.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - + + + + #{new java.util.Random().nextInt()} + test + +