问题描述:
在写代码测试的时候,发现事务并没有起效,抛出异常之后,事务并没有回滚。但是这段代码我上星期才刚测试完,是没问题的,但是今天怎么测试都是不行.手动在启动类上贴@EnableTransactionManagement或者使用xml的方式配置事务都是不起效.
接着通过断点的方式查看该sevice对象,发现并没有被代理.
后面通过排除法的方式,发现把Shiro相关配置注释掉后就没问题了.
原因分析
在Shiro配置中,如果要@RequiresPermissions生效需要在配置文件中添加如下配置:
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
/**
* 开启aop注解支持
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
DefaultAdvisorAutoProxyCreator
就是通过AOP的方式对贴了@RequiredPermission
的类进行增强,生成对应的代理类对象.
但是由于ShiroFilterFactoryBean实现了FactoryBean接口,所以它会提前被初始化。又因为SecurityManager,SecurityManager依赖于Realm实现类、Realm实现类又依赖于UserService,所以引发所有相关的bean提前初始化,导致UserService并没有被事务AOP包裹着.
所以就出现了事务无效的问题.
解决方案
在Realm中Service声明上加入@Lazy注解,延迟Realm实现中Service对象的初始化时间,这样就可以保证Service实际初始化的时候会被BeanPostProcessor拦截,创建具有事务功能的代理对象。
@Component
public class UserRealm extends AuthorizingRealm {
@Autowired
@Lazy
private IUserService userService;
@Autowired
@Lazy
private IPermissionService permissionService;
@Override
public String getName() {
return "UserRealm";
}
.....
}