問題描述:
在寫代碼測試的時(shí)候,發(fā)現(xiàn)事務(wù)并沒有起效,拋出異常之后,事務(wù)并沒有回滾。但是這段代碼我上星期才剛測試完,是沒問題的,但是今天怎么測試都是不行.手動(dòng)在啟動(dòng)類上貼@EnableTransactionManagement或者使用xml的方式配置事務(wù)都是不起效.
接著通過斷點(diǎn)的方式查看該sevice對(duì)象,發(fā)現(xiàn)并沒有被代理.
后面通過排除法的方式,發(fā)現(xiàn)把Shiro相關(guān)配置注釋掉后就沒問題了.
原因分析
在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的方式對(duì)貼了@RequiredPermission的類進(jìn)行增強(qiáng),生成對(duì)應(yīng)的代理類對(duì)象.
但是由于ShiroFilterFactoryBean實(shí)現(xiàn)了FactoryBean接口,所以它會(huì)提前被初始化。又因?yàn)镾ecurityManager,SecurityManager依賴于Realm實(shí)現(xiàn)類、Realm實(shí)現(xiàn)類又依賴于UserService,所以引發(fā)所有相關(guān)的bean提前初始化,導(dǎo)致UserService并沒有被事務(wù)AOP包裹著.
所以就出現(xiàn)了事務(wù)無效的問題.
解決方案
在Realm中Service聲明上加入@Lazy注解,延遲Realm實(shí)現(xiàn)中Service對(duì)象的初始化時(shí)間,這樣就可以保證Service實(shí)際初始化的時(shí)候會(huì)被BeanPostProcessor攔截,創(chuàng)建具有事務(wù)功能的代理對(duì)象。
@Component
public class UserRealm extends AuthorizingRealm {
@Autowired
@Lazy
private IUserService userService;
@Autowired
@Lazy
private IPermissionService permissionService;
@Override
public String getName() {
return "UserRealm";
}
.....
}