抛错:
Singleton bean creation not allowed while the singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)
原因:
mq未停服,不断的消费mq. 此时. spring正在关闭容器. context.close,destroy. 整个容器正在关闭中.
事务拦截器获取bean通过applicationContext里获取.判断容器正在关闭,拒绝获取bean.抛错.
解决方案:
分析: 自然想到通过bean的生命周期来实现关闭mq消费线程,DisposableBean接口或者 "-method" 两个方式.
看看spring的关闭流程 ,ClassPathXmlApplicationContext#doClose()方法内:
故选用ApplicationListener<ContextClosedEvent>接口,细节见下文附录.
总结: lifeCycle类和bean的生命周期不太一致.
start如果不调用context.start() 是不会启动的. context构造函数默认调用的是fresh().
先执行生命周期关闭,执行lifeCycle.stop. 再进行bean的destroy().
阶段 | 执行 |
context.stop | lifeCycle.stop ContextStoppedEvent |
context.close | ContextClosedEvent lifeCycle.stop |
可理解为任务先停,再销毁工作单元.
思考题: spring的容器关闭回收,回影响 实例的依赖和和内存回收么,会影响什么?
答: bean的destroy不会影响已经实例化的object内存回收, 内存引用关系依然在,只不过在spring里的depend关系已经没有了.
附录:
2. 上图对应接口源代码:
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
public class ContextClosedEvent extends ApplicationContextEvent {
}
public class ClassPathXmlApplicationContext{
doClose(){
publishEvent(new ContextClosedEvent(this)); 如果内部配置对应的线程池,那么久可能异步,实现ApplicationListener类.
getLifecycleProcessor().onClose(); 实现lifeCycle类. smartLiefeCycle是异步
}
}
3. 上图调用堆栈
DisposableBeanAdapter.invokeCustomDestroyMethod(Method) line: 300
DisposableBeanAdapter.destroy() line: 226
DefaultListableBeanFactory(DefaultSingletonBeanRegistry).destroyBean(String, DisposableBean) line: 498
DefaultListableBeanFactory(DefaultSingletonBeanRegistry).destroySingleton(String) line: 474
DefaultListableBeanFactory(DefaultSingletonBeanRegistry).destroySingletons() line: 442 设置 this.singletonsCurrentlyInDestruction = true; 标记容器正在关闭中.
ClassPathXmlApplicationContext(AbstractApplicationContext).destroyBeans() line: 1066
ClassPathXmlApplicationContext(AbstractApplicationContext).doClose() line: 1040
ClassPathXmlApplicationContext(AbstractApplicationContext).close() line: 988
通过eclipse call hiearchary 无法得到这个调用堆栈.
contex