org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'eurekaAutoServiceRegistration': Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:216) [spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1078) [spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.event.ApplicationListenerMethodAdapter.getTargetBean(ApplicationListenerMethodAdapter.java:283) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:253) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:177) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:140) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393) [spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:399) [spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347) [spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:991) [spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:958) [spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.cloud.context.named.NamedContextFactory.destroy(NamedContextFactory.java:76) [spring-cloud-context-1.2.3.RELEASE.jar:1.2.3.RELEASE]
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:272) [spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:578) [spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:554) [spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:961) [spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:523) [spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.destroySingletons(FactoryBeanRegistrySupport.java:230) [spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:968) [spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1030) [spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1006) [spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.context.support.AbstractApplicationContext$2.run(AbstractApplicationContext.java:929) [spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
The root cause is when closing ApplicationContext, it will destroy all singleton bean, eurekaAutoServiceRegistration
is destroyed first, then feignContext
. When destroy feignContext
, it will close the ApplicationContext associated with each FeignClient. Since eurekaAutoServiceRegistration
listen on ContextClosedEvent, those events will be sent to that bean. Unfortunately because it has been destroyed, so we got the above exception (try to create bean in destruction).
@EventListener(ContextClosedEvent.class)
public void onApplicationEvent(ContextClosedEvent event) {
// register in case meta data changed
stop();
}
根本原因是:当关闭ApplicationContext,会关闭所有的单例:先是eurekaAutoServiceRegistration,
然后是feignContext。
当关闭feignContext
时,会关闭与每个FeignClient
关联的ApplicationContext,因为eurekaAutoServiceRegistration
监听ContextClosedEvent,ContextClosedEvent的所有事件将会被发送到那个bean上,因为它已经被关闭了,所以会出现上面异常。
Found a workaround. Also added more details about the root cause.
When ApplicationContext
shutdown, it will destroy all disposable beans (and beans depend on them). In this case:
FeignContext
implements DisposableBean
interfaceInetUtils
implements AutoCloseable
interfaceEurekaServiceRegistry
has a public close methodEurekaAutoServiceRegistration
depends on InetUtils
and EurekaServiceRegistry
beans, so if either bean is destroyed, EurekaAutoServiceRegistration
will be destroyed.Destroy follow First In, Last Out order. Usually application code will not depends on InetUtils or EurekaServiceRegistry, but they depends on FeignClient interfaces. That means FeignContext
usually get instituted before InetUtils
and EurekaServiceRegistry
, so it will be destroyed after them:
InetUtils
or EurekaServiceRegistry
to be destroyed.EurekaAutoServiceRegistration
first.InetUtils
and EurekaServiceRegistry
.FeignContext
which will shutdown all ApplicationContext
associated with FeignClients.EurekaAutoServiceRegistration
listen on ContextClosedEvent
but it has been destroyed. ApplicationContext will try to create it again, got exception.Workaround
Make sure InetUtils
and EurekaServiceRegistry
are instituted before FeignContext
. So the sequence become:
FeignContext
which will shutdown all ApplicationContext
associated with FeignClients.EurekaAutoServiceRegistration
listen on ContextClosedEvent
and processed those events.InetUtils
or EurekaServiceRegistry
to be destroyed.EurekaAutoServiceRegistration
first.InetUtils
and EurekaServiceRegistry
.There are several ways to do that. The recommended solution is implement a BeanFactoryPostProcessor:
@Component
public class FeignBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition bd = beanFactory.getBeanDefinition("feignContext");
bd.setDependsOn("eurekaServiceRegistry", "inetUtils");
}
}
This workaround will eliminate the exception, but the problem is still there in EurekaAutoServiceRegistration.onApplicationEvent
and FeignContext.destroy
.
参考:
https://github.com/spring-cloud/spring-cloud-netflix/issues/1952中crmky