From 68fb5789ca652d3b6c9e7cc9a0edb6423e2549ac Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 13 Jul 2016 09:49:09 +0100 Subject: [PATCH] Create one SpringApplicationAdminMXBeanRegistrar per context hierarchy Previously, one SpringApplicationAdminMXBeanRegistrar was created per context. When there was more then one context this would result in a javax.management.InstanceAlreadyExistsException being thrown as an attempt was made to register the MBean more than once. This commit updates SpringApplicationAdminJmxAutoConfiguration so that the registrar is only created when there's no such existing bean in the context hierarchy. Closes gh-6378 --- ...gApplicationAdminJmxAutoConfiguration.java | 5 ++- ...icationAdminJmxAutoConfigurationTests.java | 37 ++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfiguration.java index 59ebd609f5d..59112535299 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.admin.SpringApplicationAdminMXBean; import org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.context.annotation.Bean; @@ -34,6 +35,7 @@ import org.springframework.jmx.export.MBeanExporter; * for internal use only. * * @author Stephane Nicoll + * @author Andy Wilkinson * @since 1.3.0 * @see SpringApplicationAdminMXBean */ @@ -60,6 +62,7 @@ public class SpringApplicationAdminJmxAutoConfiguration { private Environment environment; @Bean + @ConditionalOnMissingBean public SpringApplicationAdminMXBeanRegistrar springApplicationAdminRegistrar() throws MalformedObjectNameException { String jmxName = this.environment.getProperty(JMX_NAME_PROPERTY, diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfigurationTests.java index 7fdbb444d14..d46f96423ec 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,9 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; @@ -49,6 +52,7 @@ import static org.junit.Assert.fail; * Tests for {@link SpringApplicationAdminJmxAutoConfiguration}. * * @author Stephane Nicoll + * @author Andy Wilkinson */ public class SpringApplicationAdminJmxAutoConfigurationTests { @@ -131,6 +135,37 @@ public class SpringApplicationAdminJmxAutoConfigurationTests { assertEquals(String.valueOf(expected), actual); } + @Test + public void onlyRegisteredOnceWhenThereIsAChildContext() throws Exception { + SpringApplicationBuilder parentBuilder = new SpringApplicationBuilder().web(false) + .sources(JmxAutoConfiguration.class, + SpringApplicationAdminJmxAutoConfiguration.class); + SpringApplicationBuilder childBuilder = parentBuilder + .child(JmxAutoConfiguration.class, + SpringApplicationAdminJmxAutoConfiguration.class) + .web(false); + ConfigurableApplicationContext parent = null; + ConfigurableApplicationContext child = null; + + try { + parent = parentBuilder.run("--" + ENABLE_ADMIN_PROP); + child = childBuilder.run("--" + ENABLE_ADMIN_PROP); + BeanFactoryUtils.beanOfType(parent.getBeanFactory(), + SpringApplicationAdminMXBeanRegistrar.class); + this.thrown.expect(NoSuchBeanDefinitionException.class); + BeanFactoryUtils.beanOfType(child.getBeanFactory(), + SpringApplicationAdminMXBeanRegistrar.class); + } + finally { + if (parent != null) { + parent.close(); + } + if (child != null) { + child.close(); + } + } + } + private ObjectName createDefaultObjectName() { return createObjectName(DEFAULT_JMX_NAME); }