Configure ChildManagementContext container type

Ensure any ChildManagementContext created to start a management server
on a different port uses the same EmbeddedServletContainerFactory type.

Fixes gh-5474
This commit is contained in:
Phillip Webb 2016-04-09 23:25:16 -07:00
parent d7e56abdf3
commit a1284bce61
2 changed files with 74 additions and 1 deletions

View File

@ -30,11 +30,14 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.mvc.ManagementServletContext;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
@ -55,6 +58,7 @@ import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfigurat
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@ -104,6 +108,8 @@ public class EndpointWebMvcAutoConfiguration
private static final Log logger = LogFactory
.getLog(EndpointWebMvcAutoConfiguration.class);
private static final ConfigurableListableBeanFactory BeanDefinitionRegistry = null;
private ApplicationContext applicationContext;
private BeanFactory beanFactory;
@ -164,7 +170,7 @@ public class EndpointWebMvcAutoConfiguration
}
private void createChildManagementContext() {
final AnnotationConfigEmbeddedWebApplicationContext childContext = new AnnotationConfigEmbeddedWebApplicationContext();
AnnotationConfigEmbeddedWebApplicationContext childContext = new AnnotationConfigEmbeddedWebApplicationContext();
childContext.setParent(this.applicationContext);
childContext.setNamespace("management");
childContext.setId(this.applicationContext.getId() + ":management");
@ -172,12 +178,30 @@ public class EndpointWebMvcAutoConfiguration
PropertyPlaceholderAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class);
registerEmbeddedServletContainerFactory(childContext);
CloseEventPropagationListener.addIfPossible(this.applicationContext,
childContext);
childContext.refresh();
managementContextResolver().setApplicationContext(childContext);
}
private void registerEmbeddedServletContainerFactory(
AnnotationConfigEmbeddedWebApplicationContext childContext) {
try {
EmbeddedServletContainerFactory servletContainerFactory = this.applicationContext
.getBean(EmbeddedServletContainerFactory.class);
ConfigurableListableBeanFactory beanFactory = childContext.getBeanFactory();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
registry.registerBeanDefinition("embeddedServletContainerFactory",
new RootBeanDefinition(servletContainerFactory.getClass()));
}
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore and assume auto-configuration
}
}
/**
* Add an alias for 'local.management.port' that actually resolves using
* 'local.server.port'.

View File

@ -58,7 +58,9 @@ import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebAppl
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.ApplicationContext;
@ -85,6 +87,7 @@ import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -177,6 +180,35 @@ public class EndpointWebMvcAutoConfigurationTests {
assertAllClosed();
}
@Test
public void onDifferentPortWithSpecificContainer() throws Exception {
this.applicationContext.register(SpecificContainerConfig.class, RootConfig.class,
DifferentPortConfig.class, EndpointConfig.class, BaseConfiguration.class,
EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class);
this.applicationContext.refresh();
assertContent("/controller", ports.get().server, "controlleroutput");
assertContent("/endpoint", ports.get().server, null);
assertContent("/controller", ports.get().management, null);
assertContent("/endpoint", ports.get().management, "endpointoutput");
assertContent("/error", ports.get().management, startsWith("{"));
ApplicationContext managementContext = this.applicationContext
.getBean(ManagementContextResolver.class).getApplicationContext();
List<?> interceptors = (List<?>) ReflectionTestUtils.getField(
managementContext.getBean(EndpointHandlerMapping.class), "interceptors");
assertEquals(1, interceptors.size());
EmbeddedServletContainerFactory parentContainerFactory = this.applicationContext
.getBean(EmbeddedServletContainerFactory.class);
EmbeddedServletContainerFactory managementContainerFactory = managementContext
.getBean(EmbeddedServletContainerFactory.class);
assertThat(parentContainerFactory,
instanceOf(SpecificEmbeddedServletContainerFactory.class));
assertThat(managementContainerFactory,
instanceOf(SpecificEmbeddedServletContainerFactory.class));
assertThat(managementContainerFactory, not(sameInstance(parentContainerFactory)));
this.applicationContext.close();
assertAllClosed();
}
@Test
public void onDifferentPortAndContext() throws Exception {
this.applicationContext.register(RootConfig.class, EndpointConfig.class,
@ -611,6 +643,16 @@ public class EndpointWebMvcAutoConfigurationTests {
}
@Configuration
public static class SpecificContainerConfig {
@Bean
public SpecificEmbeddedServletContainerFactory embeddedServletContainerFactory() {
return new SpecificEmbeddedServletContainerFactory();
}
}
@Configuration
@Import(ServerPortConfig.class)
public static class DifferentPortConfig {
@ -638,6 +680,7 @@ public class EndpointWebMvcAutoConfigurationTests {
}
protected static class TestInterceptor extends HandlerInterceptorAdapter {
private int count = 0;
@Override
@ -650,6 +693,7 @@ public class EndpointWebMvcAutoConfigurationTests {
public int getCount() {
return this.count;
}
}
}
@ -730,4 +774,9 @@ public class EndpointWebMvcAutoConfigurationTests {
}
private static class SpecificEmbeddedServletContainerFactory
extends TomcatEmbeddedServletContainerFactory {
}
}