Shiro 导致 Spring 事务失效

Shiro 导致 Spring 事务失效

前段时间将 Shiro 作为权限模块整合到 Spring 中使用,也发了篇整合相关的文章《Shiro 方法上有权限注解的时候才鉴权》,讲如何实现在有打注解时才校验权限。

在集成后的项目中开发时出现有个 Service 的事务是无效的,@Transactional 注解无任何作用。检查后发现这个 Service 是在 Shiro 的 Realm 类中使用 @Autowired 注入的。

介绍

印象中,Shiro 集成到 Spring 中是会影响事务的,但可以通过配置 ProxyTargetClass 来使注解继续有效。配置时基本都会配置下面这样的 Bean:

1
2
3
4
5
6
7
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}

DefaultAdvisorAutoProxyCreator 类主要用于 Spring AOP 中的 Advisor 进行自动代理的实现,@Transactional 的实现依赖于 DefaultAdvisorAutoProxyCreator
DefaultAdvisorAutoProxyCreator 会在 bean 初始化的时候处理所有的 Advisor 并对需要的 bean 进行代理,将 Advisor 插入 bean 代理中,@Transactional 的处理正是利用一个 Advisor 进行的(BeanFactoryTransactionAttributeSourceAdvisor)。

在上面的代码中,DefaultAdvisorAutoProxyCreatorlifecycleBeanPostProcessor 后,意味着在 lifecycleBeanPostProcessor 处理的代码中如果注入了某个 bean,这个 bean 将不会被 DefaultAdvisorAutoProxyCreator 处理到(已经被先实例化)。

@Transactional@Async@Cacheable 等依赖 DefaultAdvisorAutoProxyCreator 进行实现的功能都不能生效。

LifecycleBeanPostProcessor 类是 Shiro 提供的一个 BeanPostProcessor 类,其中的 postProcessBeforeInitialization 方法调用了 Spring Context 中实现了 Initializable 接口的类的 init() 方法。在上面的情景中,我定义的 Realm 类都是 Initializable 接口的实现类,同时又使用了 @Component 注解,导致 Service 被提前注入而未被 AOP 代理。

解决方法

1. @Lazy 法

将 Realm 中的 @Autowired 对象全加上 @Lazy,使其延迟加载

2. 手动 getBean

在用到的时候再从 spring context 中取出对应的 bean

作者

Jakes Lee

发布于

2018-05-20

更新于

2021-11-18

许可协议

评论