Do not change availability on close unless context is active
Previously, an AvailabilityChangeEvent was published when the servlet and reactive web server application contexts were closed, irrespective of whether or not the context was active. This caused problems when the context was not active due to a refresh failure as the event publication could then trigger bean creation and post-processing that relied upon beans that had been destroyed when cleaning up after the refresh failure. The most commonly seen symptom was a missing importRegistry bean that is required by ImportAwareBeanPostProcessor. This commit updates the two web server application contexts to only publish the availability change event if the context is active. Fixes gh-21588
This commit is contained in:
parent
b5673db6fa
commit
f17f1255a4
|
|
@ -136,7 +136,9 @@ public class ReactiveWebServerApplicationContext extends GenericReactiveWebAppli
|
|||
|
||||
@Override
|
||||
protected void doClose() {
|
||||
AvailabilityChangeEvent.publish(this, ReadinessState.REFUSING_TRAFFIC);
|
||||
if (this.isActive()) {
|
||||
AvailabilityChangeEvent.publish(this, ReadinessState.REFUSING_TRAFFIC);
|
||||
}
|
||||
super.doClose();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,7 +164,9 @@ public class ServletWebServerApplicationContext extends GenericWebApplicationCon
|
|||
|
||||
@Override
|
||||
protected void doClose() {
|
||||
AvailabilityChangeEvent.publish(this, ReadinessState.REFUSING_TRAFFIC);
|
||||
if (this.isActive()) {
|
||||
AvailabilityChangeEvent.publish(this, ReadinessState.REFUSING_TRAFFIC);
|
||||
}
|
||||
super.doClose();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.List;
|
|||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.availability.AvailabilityChangeEvent;
|
||||
import org.springframework.boot.availability.ReadinessState;
|
||||
|
|
@ -141,6 +142,18 @@ class ReactiveWebServerApplicationContextTests {
|
|||
.isEqualTo(ReadinessState.REFUSING_TRAFFIC);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenContextIsNotActiveThenCloseDoesNotChangeTheApplicationAvailability() {
|
||||
addWebServerFactoryBean();
|
||||
addHttpHandlerBean();
|
||||
TestApplicationListener listener = new TestApplicationListener();
|
||||
this.context.addApplicationListener(listener);
|
||||
this.context.registerBeanDefinition("refreshFailure", new RootBeanDefinition(RefreshFailure.class));
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh);
|
||||
this.context.close();
|
||||
assertThat(listener.receivedEvents()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenTheContextIsRefreshedThenASubsequentRefreshAttemptWillFail() {
|
||||
addWebServerFactoryBean();
|
||||
|
|
@ -186,4 +199,12 @@ class ReactiveWebServerApplicationContextTests {
|
|||
|
||||
}
|
||||
|
||||
static class RefreshFailure {
|
||||
|
||||
RefreshFailure() {
|
||||
throw new RuntimeException("Fail refresh");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,6 +182,17 @@ class ServletWebServerApplicationContextTests {
|
|||
ContextClosedEvent.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenContextIsNotActiveThenCloseDoesNotChangeTheApplicationAvailability() {
|
||||
addWebServerFactoryBean();
|
||||
TestApplicationListener listener = new TestApplicationListener();
|
||||
this.context.addApplicationListener(listener);
|
||||
this.context.registerBeanDefinition("refreshFailure", new RootBeanDefinition(RefreshFailure.class));
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh);
|
||||
this.context.close();
|
||||
assertThat(listener.receivedEvents()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void cannotSecondRefresh() {
|
||||
addWebServerFactoryBean();
|
||||
|
|
@ -531,4 +542,12 @@ class ServletWebServerApplicationContextTests {
|
|||
|
||||
}
|
||||
|
||||
static class RefreshFailure {
|
||||
|
||||
RefreshFailure() {
|
||||
throw new RuntimeException("Fail refresh");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue