Propogate startup failures to management context
Update EndpointWebMvcAutoConfiguration so that ApplicationFailedEvents cause the management context to close. Prior to this commit if an application failed to start (for example because `server.port` was already in use) the management context would remain open and the application would not exit. Fixes gh-5388
This commit is contained in:
parent
f0b6d346d7
commit
68983400fb
|
@ -54,9 +54,11 @@ 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.boot.context.event.ApplicationFailedEvent;
|
||||
import org.springframework.boot.web.filter.ApplicationContextHeaderFilter;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -172,7 +174,7 @@ public class EndpointWebMvcAutoConfiguration
|
|||
EmbeddedServletContainerAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class);
|
||||
registerEmbeddedServletContainerFactory(childContext);
|
||||
CloseEventPropagationListener.addIfPossible(this.applicationContext,
|
||||
CloseManagementContextListener.addIfPossible(this.applicationContext,
|
||||
childContext);
|
||||
childContext.refresh();
|
||||
managementContextResolver().setApplicationContext(childContext);
|
||||
|
@ -235,25 +237,42 @@ public class EndpointWebMvcAutoConfiguration
|
|||
}
|
||||
|
||||
/**
|
||||
* {@link ApplicationListener} to propagate the {@link ContextClosedEvent} from a
|
||||
* parent to a child.
|
||||
* {@link ApplicationListener} to propagate the {@link ContextClosedEvent} and
|
||||
* {@link ApplicationFailedEvent} from a parent to a child.
|
||||
*/
|
||||
private static class CloseEventPropagationListener
|
||||
implements ApplicationListener<ContextClosedEvent> {
|
||||
private static class CloseManagementContextListener
|
||||
implements ApplicationListener<ApplicationEvent> {
|
||||
|
||||
private final ApplicationContext parentContext;
|
||||
|
||||
private final ConfigurableApplicationContext childContext;
|
||||
|
||||
CloseEventPropagationListener(ApplicationContext parentContext,
|
||||
CloseManagementContextListener(ApplicationContext parentContext,
|
||||
ConfigurableApplicationContext childContext) {
|
||||
this.parentContext = parentContext;
|
||||
this.childContext = childContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextClosedEvent event) {
|
||||
if (event.getApplicationContext() == this.parentContext) {
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
if (event instanceof ContextClosedEvent) {
|
||||
onContextClosedEvent((ContextClosedEvent) event);
|
||||
}
|
||||
if (event instanceof ApplicationFailedEvent) {
|
||||
onApplicationFailedEvent((ApplicationFailedEvent) event);
|
||||
}
|
||||
};
|
||||
|
||||
private void onContextClosedEvent(ContextClosedEvent event) {
|
||||
propagateCloseIfNecessary(event.getApplicationContext());
|
||||
}
|
||||
|
||||
private void onApplicationFailedEvent(ApplicationFailedEvent event) {
|
||||
propagateCloseIfNecessary(event.getApplicationContext());
|
||||
}
|
||||
|
||||
private void propagateCloseIfNecessary(ApplicationContext applicationContext) {
|
||||
if (applicationContext == this.parentContext) {
|
||||
this.childContext.close();
|
||||
}
|
||||
}
|
||||
|
@ -268,7 +287,7 @@ public class EndpointWebMvcAutoConfiguration
|
|||
private static void add(ConfigurableApplicationContext parentContext,
|
||||
ConfigurableApplicationContext childContext) {
|
||||
parentContext.addApplicationListener(
|
||||
new CloseEventPropagationListener(parentContext, childContext));
|
||||
new CloseManagementContextListener(parentContext, childContext));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -62,10 +62,12 @@ import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory
|
|||
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
|
||||
import org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer;
|
||||
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||
import org.springframework.boot.context.event.ApplicationFailedEvent;
|
||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
||||
import org.springframework.boot.testutil.Matched;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
@ -282,6 +284,22 @@ public class EndpointWebMvcAutoConfigurationTests {
|
|||
assertContent("/endpoint", managementPort, "endpointoutput");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDifferentPortWithPrimaryFailure() throws Exception {
|
||||
this.applicationContext.register(RootConfig.class, EndpointConfig.class,
|
||||
DifferentPortConfig.class, BaseConfiguration.class,
|
||||
EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class);
|
||||
this.applicationContext.refresh();
|
||||
ApplicationContext managementContext = this.applicationContext
|
||||
.getBean(ManagementContextResolver.class).getApplicationContext();
|
||||
ApplicationFailedEvent event = mock(ApplicationFailedEvent.class);
|
||||
given(event.getApplicationContext()).willReturn(this.applicationContext);
|
||||
this.applicationContext.publishEvent(event);
|
||||
assertThat(((ConfigurableApplicationContext) managementContext).isActive())
|
||||
.isFalse();
|
||||
this.applicationContext.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disabled() throws Exception {
|
||||
this.applicationContext.register(RootConfig.class, EndpointConfig.class,
|
||||
|
|
Loading…
Reference in New Issue