今天在做项目的时候,遇到了一个非常扯淡的问题,困扰了我大半天才解决。不得不说,springboot虽然简单,但是坑还是不少!
问题描述:
在整合springboot双数据源的时候,大致的步骤可以看我第一篇写的步骤,第一篇写的虽然是在SSM环境下搭建的,但是原理其实和springboot差不多。
然而我花了20分钟将双数据源给搭建完毕后,却出现了一个非常诡异的错误,就是在我的aop配置类上却出了问题。
这是我之前的配置写法,在springboot中我是转换为了一个配置类,却比这个xml配置要更加的简单。通过环绕通知判断定义的数据源注解的位置,从而根据反射得到mapper方法进行切换数据源
<aop:config>
<!--设置事务的优先级-->
<aop:aspect ref="dataSwitchAop" order="0">
<!--拦截所有的service的方法-->
<!--当然也可以拦截Controller方法,这里设置的是拦截service-->
<aop:pointcut id="dataSourcePointcut" expression="execution(* com.ilongsay.service.*Service..*(..))"/>
<aop:before method="intercept" pointcut-ref="dataSourcePointcut"/>
<aop:after method="clearDataSource" pointcut-ref="dataSourcePointcut"/>
</aop:aspect>
</aop:config>
springboot中的设置:但是在实际的操作中,我却发现,数据源根本切换不了啊,我明明在mapper上添加了这个dataSource的注解了啊。。。。。。。
@Aspect
@Order(1)
@Component
public class DataSourceAspect
{
protected Logger logger = LoggerFactory.getLogger(getClass());
@Pointcut("@annotation(com.xxxx.xxxx.annotation.DataSource)")
public void dsPointCut()
{
}
@Around("dsPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable
{
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
DataSource dataSource = method.getAnnotation(DataSource.class);
if (StringUtils.isNotNull(dataSource))
{
DynamicDataSourceContextHolder.setDateSoureType(dataSource.value().name());
}
try
{
return point.proceed();
}
finally
{
// 销毁数据源 在执行方法之后
DynamicDataSourceContextHolder.clearDateSoureType();
}
}
}
然后不断地断点调试,发现这个注解加在Controller上就可以正常的切换数据源,放在service或者是mapper上就不行!
怒了。
继续断点各种测试,发现就是没有进入到这个切面中去!
怒了。
继续断点,不成功就不去吃饭。
怒了。
还是老老实实吃了饭再来调试吧
.....
还是先睡会儿再来调试吧
.....
醒了继续调试
.....
忽然灵光一闪,我换其他的service试一下,完全可以切换啊,为什么这个service就不行?
嗯.....
是不是其他地方有使用了这个Service bean?而service注入了这个mapper也导致使用不了?
对,就是这样.....
然后我开始找哪里有这个bean被引用,忽然想起来上个星期刚刚做了shiro整合cas单点登录的功能,等等,是不是在shiro中引用了?而且恰好我上个项目没有使用到shiro。
最后终于找到元凶。原来在shiro中定义的注入的ServiceBean都不能正常的切换数据源,包括它们引用的注入的mapper!
最后解决的办法就是:注入的上面加一个懒加载的注解@Lazy 的这个注解。
具体原因未知。
然后可以完美的进行数据库的切换
public class UserRealm extends AuthorizingRealm
{
private static final Logger log = LoggerFactory.getLogger(UserRealm.class);
@Lazy
@Autowired
private ISysMenuService menuService;
@Lazy
@Autowired
private ISysRoleService roleService;
@Lazy
@Autowired
private SysLoginService loginService;
@Lazy
@Autowired
private OnlineSessionDAO onlineSessionDAO;