记录一次由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的加载。

猜你喜欢

转载自blog.csdn.net/sinat_33472737/article/details/109503861