Yes, the Spring application contexts do propagate events from the child context to all its ancestors recursively.
The following AbstractApplicationContext code takes responsibility for this:
/**
* Publish the given event to all listeners.
* @param event the event to publish (may be an {@link ApplicationEvent}
* or a payload object to be turned into a {@link PayloadApplicationEvent})
* @param eventType the resolved event type, if known
* @since 4.2
*/
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
}
}
// 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);
}
else {
this.parent.publishEvent(event);
}
}
}
As you see in the end of the publishMethod body, if there is a parent then any event will be propagated to it too.
On the contrary, events from the parent won't be propagated to the children since the parent doesn't know about the children.
If you don't want to propagate events, you can simply do this (instead of setting a parent to your child context):
yourChildApplicationContext.addBeanFactoryPostProcessor(beanFactory -> {
beanFactory.setParentBeanFactory(parentContext.getBeanFactory());
});
Or, if your child context is a GenericApplicationContext (AnnotationConfigApplicationContext, GenericGroovyApplicationContext, GenericXmlApplicationContext, StaticApplicationContext), you can even simplify more:
yourChildApplicationContext.getDefaultListableBeanFactory()
.setParentBeanFactory(parentContext.getBeanFactory());