记录一次由SqlSessionFactory引起的BeanCurrentlyInCreationException

一、项目概况

        项目中使用了mybatis-plus-boot-starter这个依赖。为了实现数据权限同一处理,自定义了一个数据权限的拦截器,该拦截器实现了mybatis的Interceptor接口(public class DataScopeInterceptor implements Interceptor)。项目中还使用了shiro做权限处理。

二、分析

       由于ShiroFilterFactoryBean实现了BeanPostProcessor接口(spring扩展接口),所以项目在启动时优先创建该bean的实例。ShiroFilterFactoryBean中的SecurityManager中的ShiroRealm为自定义的Realm(ShiroRealm).

而ShiroRealm中注入了自定义的service,如Aservice,而Aservice中注入了Amapper.因为所有的mapper都是会注入SqlSessionFactory的,所以项目启动时加载bean的流程如下:

ShiroFilterFactoryBean》SecurityManager》ShiroRealm》Aservice》Amapper》SqlSessionFactory,而在创建SqlSessionFactory时会去加载MybatisPlusAutoConfiguration,这里有一个问题需要注意,那就是SqlSessionFactory这个bean并没有放入到spring的三级缓存中singletonFactories,加载MybatisPlusAutoConfiguration是会去加载所有的拦截器,而我们的拦截器DataScopeInterceptor 中注入了Bservice,而Bservice中注入了Bmapper,所以整体加载bean的流程是这样的:

ShiroFilterFactoryBean》SecurityManager》ShiroRealm》Aservice》Amapper》SqlSessionFactory》MybatisPlusAutoConfiguration》DataScopeInterceptor 》Bservice》Bmapper》SqlSessionFactory

由于第一次加载SqlSessionFactory是未放入到spring的三级缓存中singletonFactories,所以会再次加载SqlSessionFactory。因为每创建一个bean前,都会做如下处理:

	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

所以第一次创建SqlSessionFactory时该方法成功,但第二次由于singletonsCurrentlyInCreation中已有SqlSessionFactory,所以抛出BeanCurrentlyInCreationException异常。

三、解决方案

第一种方案(推荐):在DataScopeInterceptor依赖的Bservice上添加@Lazy

第二种方案:将Bservice放入到Aservice中的第一个依赖,Bservice未使用,但思路就是在DataScopeInterceptor后不再有Bmapper的创建。当然DataScopeInterceptor中不能有其它mapper存在

四、总结

        由于SqlSessionFactory》MybatisPlusAutoConfiguration,而SqlSessionFactory是未放入到spring的三级缓存中singletonFactories,所以在加载MybatisPlusAutoConfiguration完成之前,不能够再次有SqlSessionFactory的加载,也就是不能有其它mapper的加载。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
SqlSessionFactory是MyBatis框架的核心对象之一。它是一个单例的数据库映射关系经过编译后的内存镜像。通过SqlSessionFactory对象,可以创建SqlSession对象,用于执行SQL语句和操作数据库。 要创建SqlSessionFactory对象,可以通过SqlSessionFactoryBuilder对象来构建。SqlSessionFactoryBuilder可以从XML配置文件或一个预先定制的Configuration对象构建SqlSessionFactory的实例。 每个MyBatis应用程序都以一个SqlSessionFactory对象的实例为核心。SqlSessionFactory是线程安全的,一旦被创建,应该在应用程序的整个生命周期内存在。因此,在应用程序运行期间,不要重复创建多次SqlSessionFactory对象,推荐使用单例模式。 以下是SqlSessionFactory接口的一些方法: - openSession():使用默认设置创建一个SqlSession对象。 - openSession(boolean autoCommit):根据指定的参数创建一个SqlSession对象。 - openSession(Connection connection):根据给定的数据库连接创建一个SqlSession对象。 - openSession(TransactionIsolationLevel level):根据给定的事务隔离级别创建一个SqlSession对象。 - openSession(ExecutorType execType):根据给定的执行器类型创建一个SqlSession对象。 - openSession(ExecutorType execType, boolean autoCommit):根据给定的执行器类型和自动提交参数创建一个SqlSession对象。 - openSession(ExecutorType execType, TransactionIsolationLevel level):根据给定的执行器类型和事务隔离级别创建一个SqlSession对象。 - openSession(ExecutorType execType, Connection connection):根据给定的执行器类型和数据库连接创建一个SqlSession对象。 - getConfiguration():获取配置对象Configuration。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值