From 0f73a69033e8ecc62af0a7a63167c09a2af495d7 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 7 Feb 2019 15:56:46 +0100 Subject: [PATCH] AbstractApplicationContext resets local listeners to pre-refresh state Closes gh-22325 --- .../support/AbstractApplicationContext.java | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) 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 ee1603ef174..54c3850158a 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -212,7 +212,11 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader /** Statically specified listeners. */ private final Set> applicationListeners = new LinkedHashSet<>(); - /** ApplicationEvents published early. */ + /** Local listeners registered before refresh. */ + @Nullable + private Set> earlyApplicationListeners; + + /** ApplicationEvents published before the multicaster setup. */ @Nullable private Set earlyApplicationEvents; @@ -483,7 +487,6 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader this.beanFactoryPostProcessors.add(postProcessor); } - /** * Return the list of BeanFactoryPostProcessors that will get applied * to the internal BeanFactory. @@ -578,6 +581,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader * active flag as well as performing any initialization of property sources. */ protected void prepareRefresh() { + // Switch to active. this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); @@ -591,13 +595,23 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader } } - // Initialize any placeholder property sources in the context environment + // Initialize any placeholder property sources in the context environment. initPropertySources(); - // Validate that all properties marked as required are resolvable + // Validate that all properties marked as required are resolvable: // see ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); + // Store pre-refresh ApplicationListeners... + if (this.earlyApplicationListeners == null) { + this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); + } + else { + // Reset local application listeners to pre-refresh state. + this.applicationListeners.clear(); + this.applicationListeners.addAll(this.earlyApplicationListeners); + } + // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<>(); @@ -982,6 +996,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader * @see #registerShutdownHook() */ protected void doClose() { + // Check whether an actual close attempt is necessary... if (this.active.get() && this.closed.compareAndSet(false, true)) { if (logger.isDebugEnabled()) { logger.debug("Closing " + this); @@ -1016,6 +1031,13 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader // Let subclasses do some final clean-up if they wish... onClose(); + // Reset local application listeners to pre-refresh state. + if (this.earlyApplicationListeners != null) { + this.applicationListeners.clear(); + this.applicationListeners.addAll(this.earlyApplicationListeners); + } + + // Switch to inactive. this.active.set(false); } } @@ -1302,7 +1324,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @Nullable protected MessageSource getInternalParentMessageSource() { return (getParent() instanceof AbstractApplicationContext ? - ((AbstractApplicationContext) getParent()).messageSource : getParent()); + ((AbstractApplicationContext) getParent()).messageSource : getParent()); }