Shiro 导致 Spring 事务失效
前段时间将 Shiro 作为权限模块整合到 Spring 中使用,也发了篇整合相关的文章《Shiro 方法上有权限注解的时候才鉴权》,讲如何实现在有打注解时才校验权限。
在集成后的项目中开发时出现有个 Service 的事务是无效的,@Transactional 注解无任何作用。检查后发现这个 Service 是在 Shiro 的 Realm 类中使用 @Autowired 注入的。
介绍
印象中,Shiro 集成到 Spring 中是会影响事务的,但可以通过配置 ProxyTargetClass 来使注解继续有效。配置时基本都会配置下面这样的 Bean:
1 |
|
DefaultAdvisorAutoProxyCreator 类主要用于 Spring AOP 中的 Advisor 进行自动代理的实现,@Transactional 的实现依赖于 DefaultAdvisorAutoProxyCreator。DefaultAdvisorAutoProxyCreator 会在 bean 初始化的时候处理所有的 Advisor 并对需要的 bean 进行代理,将 Advisor 插入 bean 代理中,@Transactional 的处理正是利用一个 Advisor 进行的(BeanFactoryTransactionAttributeSourceAdvisor)。
在上面的代码中,DefaultAdvisorAutoProxyCreator 在 lifecycleBeanPostProcessor 后,意味着在 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
