[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。

标签: mybatis, debug

仅有一条评论

  1. 勇哥

    李哥牛逼

添加新评论