Spring+Shiro+MybatisPlus 导致事务失效

最近在使用Shiro做权限管理的时候,在继承了AuthorizingRealm类的UserRealm自动注入了用户服务的接口ISysUserService。

@Slf4j
public class UserRealm extends AuthorizingRealm {
    @Autowired
    ISysUserService sysUserService;

    @Autowired
    ISysRoleService sysRoleService;
    }

在启动时发现,在Info日志中总是出现

2020-06-04 15:19:31.789 INFO 24676 — [ main] trationDelegate$BeanPostProcessorChecker : Bean ‘sysUserServiceImpl’ of type [org.springframework.aop.scope.ScopedProxyFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

显示ISysUserService 接口的实现类sysUserServiceImpl的后置处理器并没有完全使用,在网上找到了这一篇文章,有兴趣的小伙伴可以看一下。
【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(一)
问题大致呢,是由于在UserRealm中采取自动注入的方式注入了ISysUserService的实体Bean,由于Shiro执行链的原因,会导致ISysUserService的实体Bean提前实例化完成并启动,导致后续的BeanPostProcessor接口并没有把该Bean处理完成

@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserEntity> implements ISysUserService {

    @Autowired
    public ISysuserRoleService iSysuserRoleService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeUserAndRolesByUserId(String id) {
        //删除用户
        QueryWrapper<SysUserEntity> sysUserEntityQueryWrapper = new QueryWrapper<>();
        sysUserEntityQueryWrapper.eq("id",id);
        this.getBaseMapper().delete(sysUserEntityQueryWrapper);
        //删除用户---角色
        QueryWrapper<SysuserRoleEntity> sysuserRoleEntityQueryWrapper = new QueryWrapper<>();
        sysuserRoleEntityQueryWrapper.eq("UserId",id);
        iSysuserRoleService.remove(sysuserRoleEntityQueryWrapper);
        return true;
    }
}

因为我的用户服务类中开启了事务,所以就实体Bean的提前初始化完成就造成了没有生成事务的代理对象。
debug可以看到在该类的调用栈中,从Controller直接调用到了Service的实体类,而并不是通过事务的代理类来进行调用,所以说就没有生成这个类的事务代理对象,那么事务的使用肯定是失败的。

解决方法

  1. 我的解决方法是在该类的上方添加了@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserEntity> implements ISysUserService {

    @Autowired
    public ISysuserRoleService iSysuserRoleService;

强制生成一个Cglib代理对象,再次启动查看该类的调用栈
在这里插入图片描述可以很清楚的看到该服务的调用由事务的Cglib代理对象发起调用,此时事务就开启成功了。

  1. 另外也可以将UserRealm中的自动注入改为懒加载,就可以当ISysUserService整个初始化流程结束后再注入UserRealm中,避免了Bean的提前启动。
@Slf4j
public class UserRealm extends AuthorizingRealm {
    @Autowired
    @Lazy
    ISysUserService sysUserService;

    @Autowired
    ISysRoleService sysRoleService;
    }

如果不是因为Shiro引起的事务失效的问题并且类之间的依赖关系比较难以整理,大家可以尝试用第一种方法。

发生这样的问题主要还是不清楚Bean的初始化流程和Bean相互之间的依赖调用关系,要补。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值