AbstractApplicationContext collects early ApplicationEvents and publishes them once the multicaster is available
Issue: SPR-12902
This commit is contained in:
@@ -18,7 +18,7 @@ package org.springframework.context;
|
||||
|
||||
/**
|
||||
* Interface that encapsulates event publication functionality.
|
||||
* Serves as super-interface for ApplicationContext.
|
||||
* Serves as super-interface for {@link ApplicationContext}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
@@ -42,9 +42,10 @@ public interface ApplicationEventPublisher {
|
||||
/**
|
||||
* Notify all <strong>matching</strong> listeners registered with this
|
||||
* application of an event.
|
||||
* <p>If the specified {@code event} is not an {@link ApplicationEvent}, it
|
||||
* is wrapped in a {@code GenericApplicationEvent}.
|
||||
* <p>If the specified {@code event} is not an {@link ApplicationEvent},
|
||||
* it is wrapped in a {@link PayloadApplicationEvent}.
|
||||
* @param event the event to publish
|
||||
* @since 4.2
|
||||
* @see PayloadApplicationEvent
|
||||
*/
|
||||
void publishEvent(Object event);
|
||||
|
||||
@@ -165,6 +165,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
/** Parent context */
|
||||
private ApplicationContext parent;
|
||||
|
||||
/** Environment used by this context */
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
/** BeanFactoryPostProcessors to apply on refresh */
|
||||
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors =
|
||||
new ArrayList<BeanFactoryPostProcessor>();
|
||||
@@ -197,10 +200,10 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
private ApplicationEventMulticaster applicationEventMulticaster;
|
||||
|
||||
/** Statically specified listeners */
|
||||
private Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
|
||||
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
|
||||
|
||||
/** Environment used by this context; initialized by {@link #createEnvironment()} */
|
||||
private ConfigurableEnvironment environment;
|
||||
/** ApplicationEvents published early */
|
||||
private Set<ApplicationEvent> earlyApplicationEvents;
|
||||
|
||||
|
||||
/**
|
||||
@@ -340,7 +343,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
|
||||
}
|
||||
final ApplicationEvent applicationEvent;
|
||||
|
||||
// Decorate event as an ApplicationEvent if necessary
|
||||
ApplicationEvent applicationEvent;
|
||||
if (event instanceof ApplicationEvent) {
|
||||
applicationEvent = (ApplicationEvent) event;
|
||||
}
|
||||
@@ -350,7 +355,16 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
eventType = ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, event.getClass());
|
||||
}
|
||||
}
|
||||
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
|
||||
|
||||
// Multicast right now if possible - or lazily once the multicaster is initialized
|
||||
if (this.earlyApplicationEvents != null) {
|
||||
this.earlyApplicationEvents.add(applicationEvent);
|
||||
}
|
||||
else {
|
||||
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
|
||||
}
|
||||
|
||||
// Publish event via parent context as well...
|
||||
if (this.parent != null) {
|
||||
if (this.parent instanceof AbstractApplicationContext) {
|
||||
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
|
||||
@@ -379,7 +393,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
* @return the internal LifecycleProcessor (never {@code null})
|
||||
* @throws IllegalStateException if the context has not been initialized yet
|
||||
*/
|
||||
LifecycleProcessor getLifecycleProcessor() {
|
||||
LifecycleProcessor getLifecycleProcessor() throws IllegalStateException {
|
||||
if (this.lifecycleProcessor == null) {
|
||||
throw new IllegalStateException("LifecycleProcessor not initialized - " +
|
||||
"call 'refresh' before invoking lifecycle methods via the context: " + this);
|
||||
@@ -543,6 +557,10 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
// Validate that all properties marked as required are resolvable
|
||||
// see ConfigurablePropertyResolver#setRequiredProperties
|
||||
getEnvironment().validateRequiredProperties();
|
||||
|
||||
// Allow for the collection of early ApplicationEvents,
|
||||
// to be published once the multicaster is available...
|
||||
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -748,11 +766,21 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
for (ApplicationListener<?> listener : getApplicationListeners()) {
|
||||
getApplicationEventMulticaster().addApplicationListener(listener);
|
||||
}
|
||||
|
||||
// Do not initialize FactoryBeans here: We need to leave all regular beans
|
||||
// uninitialized to let post-processors apply to them!
|
||||
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
|
||||
for (String lisName : listenerBeanNames) {
|
||||
getApplicationEventMulticaster().addApplicationListenerBean(lisName);
|
||||
for (String listenerBeanName : listenerBeanNames) {
|
||||
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
|
||||
}
|
||||
|
||||
// Publish early application events now that we finally have a multicaster...
|
||||
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
|
||||
this.earlyApplicationEvents = null;
|
||||
if (earlyEventsToProcess != null) {
|
||||
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
|
||||
getApplicationEventMulticaster().multicastEvent(earlyEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user