Browse Source

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
pull/5980/head
Phillip Webb 10 years ago
parent
commit
68983400fb
  1. 37
      spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java
  2. 18
      spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java

37
spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java

@ -54,9 +54,11 @@ import org.springframework.boot.bind.RelaxedPropertyResolver; @@ -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 @@ -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 @@ -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 @@ -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));
}
}

18
spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java

@ -62,10 +62,12 @@ import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory @@ -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 { @@ -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…
Cancel
Save