现状:
- 未使用shiro缓存、事务的spring boot项目一切正常。
- 整合shiro安全框架,发现部分类事务Transaction注解不能正常使用。
使用方式:
- 继承AuthorizingRealm实现自定义用户权限验证。
- 使用@Autowaired 注入依赖的service服务。
分析:
通过代码分析发现UserRealm的service调试发现并没有被进行代理,事务本身的机制是通过实现BeanPostPorcessor后置处理器实现的代理(AbstractAutoProxyCreator)。
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService sysUserService;//UserService中的事务无效
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken utoken = (UsernamePasswordToken) token;
String username = utoken.getUsername();
User user = sysUserService.getUserByName(username);
return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName());
}
}
那为什么会出现事务未被代理呢,重点关注一下ShiroFilterFactoryBean对象
由于ShiroFilterFactoryBean实现了FactoryBean接口,所以它会提前被初始化。又因为SecurityManager,SecurityManager依赖于Realm实现类、Realm实现类又依赖于UserService,所以引发所有相关的bean提前初始化。
ShiroFilterFactoryBean -> SecurityManager -> Realm实现类 -> UserService
但是此时还只是ApplicationContext中registerBeanPostProcessors注册BeanPostProcessor处理器的阶段,此时AnnotationAwareAspectJAutoProxyCreator还没有注册到BeanFactory中,UserService无法生成事务代理。
解决:
1.注入ApplicationContext ,直接获取bean
2.在realm中注入service时,使用@Autowaired+@lazy注解
3.单独创建一个service直接操作mapper,然后注入到Realm中