I found the Adapter for @ EventListener was not remove when ApplicationContext close. But the ApplicationListener removed normally. this will make some error.

the code for reproduce it:

public static void main(String[] args) {
  AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(SomeBean.class);

  AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
  ctx.setParent(parent);
  ctx.refresh();


  parent.close();

  ctx.close();    // will throw exception
}

@Service
public class SomeBean {
  @EventListener(ContextClosedEvent.class)
  public void shutdown() {
    System.out.println("context closed");
  }
}

We'll see exception like:

java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@3d3fcdb0 has been closed already
    at org.springframework.context.support.AbstractApplicationContext.assertBeanFactoryActive(AbstractApplicationContext.java:1093)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1108)
    at org.springframework.context.event.ApplicationListenerMethodAdapter.getTargetBean(ApplicationListenerMethodAdapter.java:332)
    at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:297)
    at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:190)
    at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:153)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:404)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:410)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:361)
    at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1013)
    at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:979)

Comment From: jhoeller

The problematic part here is that you're closing the parent context before the child context. This is the wrong lifecycle, the dependent contexts have to get closed before any parents. An active child context may in many ways rely on the activity of its parent context, e.g. depend on certain parent beans to be active still, so this exception is fundamentally a correct indication that the parent context has been closed already - while it was still expected to be active by the child context.

We may be able to improve the cleanup of event listeners in the close phase, and/or to improve the exception being thrown by rejecting publishEvent attempts on a closed context upfront. However, in any case, the scenario above is not going to work due to the incorrect close order.

Comment From: xrayw

@jhoeller Thanks I found the error when i use spring-cloud-openfeign. It create a stand alone ApplicationContext for every @ FeignClient interface. just like

java var ctx = new AnnotationConfigApplicationContext(); ctx.setParent(parent); // the parent is the spring ApplicationContext

And it use the DisposableBean to destroy the children ApplicationContext that created for FeignClient at the NamedContextFactory class. when the children ApplicationContext close, the ContextCloseEvent will be published in parent ApplicationContext too. And will throw the exception.

Do you mean the usage of FeignClient was wrong??

Comment From: jhoeller

This is effectively a duplicate of #21988 which got addressed for 6.1.