diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java index f3159f1669..a51070cf13 100644 --- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java @@ -135,21 +135,22 @@ import org.springframework.util.ReflectionUtils; public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { - /** - * Name of the MessageSource bean in the factory. - * If none is supplied, message resolution is delegated to the parent. - * @see MessageSource - */ - public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource"; - /** * Name of the LifecycleProcessor bean in the factory. * If none is supplied, a DefaultLifecycleProcessor is used. + * @since 3.0 * @see org.springframework.context.LifecycleProcessor * @see org.springframework.context.support.DefaultLifecycleProcessor */ public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor"; + /** + * Name of the MessageSource bean in the factory. + * If none is supplied, message resolution is delegated to the parent. + * @see MessageSource + */ + public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource"; + /** * Name of the ApplicationEventMulticaster bean in the factory. * If none is supplied, a default SimpleApplicationEventMulticaster is used. @@ -433,8 +434,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } - else { - getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); + else if (this.applicationEventMulticaster != null) { + this.applicationEventMulticaster.multicastEvent(applicationEvent, eventType); } // Publish event via parent context as well... @@ -1093,6 +1094,11 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader this.applicationListeners.addAll(this.earlyApplicationListeners); } + // Reset internal delegates. + this.applicationEventMulticaster = null; + this.messageSource = null; + this.lifecycleProcessor = null; + // Switch to inactive. this.active.set(false); } diff --git a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java index d263fb1e8c..6263f62f8f 100644 --- a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java @@ -165,11 +165,27 @@ class AnnotationDrivenEventListenerTests { assertThat(events).as("Wrong number of initial context events").hasSize(1); assertThat(events.get(0).getClass()).isEqualTo(ContextRefreshedEvent.class); + this.context.start(); + List eventsAfterStart = this.eventCollector.getEvents(listener); + assertThat(eventsAfterStart).as("Wrong number of context events on start").hasSize(2); + assertThat(eventsAfterStart.get(1).getClass()).isEqualTo(ContextStartedEvent.class); + this.eventCollector.assertTotalEventsCount(2); + this.context.stop(); List eventsAfterStop = this.eventCollector.getEvents(listener); - assertThat(eventsAfterStop).as("Wrong number of context events on shutdown").hasSize(2); - assertThat(eventsAfterStop.get(1).getClass()).isEqualTo(ContextStoppedEvent.class); - this.eventCollector.assertTotalEventsCount(2); + assertThat(eventsAfterStop).as("Wrong number of context events on stop").hasSize(3); + assertThat(eventsAfterStop.get(2).getClass()).isEqualTo(ContextStoppedEvent.class); + this.eventCollector.assertTotalEventsCount(3); + + this.context.close(); + List eventsAfterClose = this.eventCollector.getEvents(listener); + assertThat(eventsAfterClose).as("Wrong number of context events on close").hasSize(4); + assertThat(eventsAfterClose.get(3).getClass()).isEqualTo(ContextClosedEvent.class); + this.eventCollector.assertTotalEventsCount(4); + + // Further events are supposed to be ignored after context close + this.context.publishEvent(new ContextClosedEvent(this.context)); + this.eventCollector.assertTotalEventsCount(4); } @Test diff --git a/spring-context/src/test/java/org/springframework/context/support/ResourceBundleMessageSourceTests.java b/spring-context/src/test/java/org/springframework/context/support/ResourceBundleMessageSourceTests.java index 3ac67704c6..7a725d93c2 100644 --- a/spring-context/src/test/java/org/springframework/context/support/ResourceBundleMessageSourceTests.java +++ b/spring-context/src/test/java/org/springframework/context/support/ResourceBundleMessageSourceTests.java @@ -32,6 +32,7 @@ import org.springframework.context.i18n.LocaleContextHolder; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatThrownBy; /** @@ -210,6 +211,8 @@ class ResourceBundleMessageSourceTests { ac.refresh(); assertThat(ac.getMessage("code1", null, "default", Locale.ENGLISH)).isEqualTo("default"); assertThat(ac.getMessage("code1", new Object[]{"value"}, "default {0}", Locale.ENGLISH)).isEqualTo("default value"); + ac.close(); + assertThatIllegalStateException().isThrownBy(() -> ac.getMessage("code1", null, "default", Locale.ENGLISH)); } @Test @@ -222,6 +225,8 @@ class ResourceBundleMessageSourceTests { ac.refresh(); assertThat(ac.getMessage("code1", null, "default", Locale.ENGLISH)).isEqualTo("default"); assertThat(ac.getMessage("code1", new Object[]{"value"}, "default {0}", Locale.ENGLISH)).isEqualTo("default value"); + ac.close(); + assertThatIllegalStateException().isThrownBy(() -> ac.getMessage("code1", null, "default", Locale.ENGLISH)); } @Test @@ -234,6 +239,8 @@ class ResourceBundleMessageSourceTests { ac.refresh(); assertThat(ac.getMessage("code1", null, "default", Locale.ENGLISH)).isEqualTo("default"); assertThat(ac.getMessage("code1", new Object[]{"value"}, "default {0}", Locale.ENGLISH)).isEqualTo("default value"); + ac.close(); + assertThatIllegalStateException().isThrownBy(() -> ac.getMessage("code1", null, "default", Locale.ENGLISH)); } @Test @@ -246,6 +253,8 @@ class ResourceBundleMessageSourceTests { ac.refresh(); assertThat(ac.getMessage("code1", null, "default", Locale.ENGLISH)).isEqualTo("default"); assertThat(ac.getMessage("code1", new Object[]{"value"}, "default {0}", Locale.ENGLISH)).isEqualTo("default value"); + ac.close(); + assertThatIllegalStateException().isThrownBy(() -> ac.getMessage("code1", null, "default", Locale.ENGLISH)); } @Test