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
This commit is contained in:
Andy Wilkinson 2016-07-13 09:49:09 +01:00
parent 49302b3449
commit 68fb5789ca
2 changed files with 40 additions and 2 deletions

View File

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

View File

@ -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);
}