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