[bugfix]sqlSessionFactoryBean在项目停机的时候报错
[debug]sqlSessionFactoryBean在项目停机的时候报错
信息如下:
[data-report-service][ WARN] 2022-05-17 09:39:19 562 [][][]- org.springframework.context.annotation.AnnotationConfigApplicationContext >>> Exception thrown from ApplicationListener handling ContextClosedEvent
org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'sqlSessionFactoryBean': 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)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
源码:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
public void onApplicationEvent(ApplicationEvent event) {
if (this.failFast && event instanceof ContextRefreshedEvent) {
// fail-fast -> check all statements are completed
this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
}
}
}
修改覆盖为:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
if (this.failFast) {
// fail-fast -> check all statements are completed
this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
}
}
}
原因:
1.FeignContext重复发送closed事件
public class FeignContext extends NamedContextFactory<FeignClientSpecification>{
// 在NamedContextFactory里面
@Override
public void destroy() {
Collection<AnnotationConfigApplicationContext> values = this.contexts.values();
for (AnnotationConfigApplicationContext context : values) {
context.close();
}
this.contexts.clear();
}
}
上面context.close();方法会重复发送ContenxtClosedEvent事件
2.SqlSessionFactoryBean销毁之后缓存及eventReceiver缓存未清除。
org.springframework.context.event.AbstractApplicationEventMulticaster.ListenerRetriever#applicationListenerBeans未清除对应的key缓存,其factoryBean的key &sqlSessionFactoryBean还存在。
3.SqlSessionFactoryBean的Event监听范围过大。
public void onApplicationEvent(ApplicationEvent event) {
if (this.failFast && event instanceof ContextRefreshedEvent) {
// fail-fast -> check all statements are completed
this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
}
}
从源码我们可以知道,我们只需要ContextRefreshedEvent事件,不需要监听全部的ApplicationEvent。
三个只要解决其中一个就可以解决这个bug。
李哥牛逼