@Transactional使自定义注解失效
Posted tommaoxiaoqi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了@Transactional使自定义注解失效相关的知识,希望对你有一定的参考价值。
问题背景:
要添加@Transactional注解,使某功能可以原子操作。
接口调用结构:controller->processor(类似Service层)->flow(类似Manager层)
附:推荐的工程结构:
1. 请求处理:(Web层)控制转发
2. 业务逻辑(Service层)具体业务逻辑
3.通用处理 (Manager层)service能力下沉,缓存,三方平台,与DAO交互。
4.数据持久(DAO层)数据访问,与mysql交互。
调用过程:
controller到processor之间是通过统一的接口分发。
所有的processor都有自定义注解,里面存接口url路径名。启动时通过ApplicationContext.getBeansOfType()把所有processor注册到一个map里。注册时getAnnocation判断自定义注解不为空,把其中的接口名作为key,真实的processor作为value。
controller收到请求,转发给统一接口,统一的接口通过收到的url接口名,从map里找到对应的processor转发。processor直接调对应的flow。
问题现象:
在processor的方法上加@Transactional注解。此时调不到对应的processor。
调试发现,在启动注册时,该processor里就没有注册进来,根据url在map里自然找不到对应的processor。没注册进来发生在clazz.getAnnocation时候得到的为空。
从IOC容器中获取所有processor的bean的时候,获取到了所有processor。但是在含有@Transaction注解的那个processor在获得自定义注解内容的时候获取不到。
所以是@Transaction使通过getAnnotation()获取自定义注解失效。
产生原因:
@Transaction 的原理是AOP代理,从而使IOC中的bean是代理类,不是真实bean。自定义注解并没有继承过来,所以在代理类上找不到自定义注解。
解决方法:
1. 自定义注解在声明的时候加上 @Inherited,表明该注解是可以被子类继承的。父类有该注解子类也可以获取该注解。对类的继承有效,对接口的继承和实现无效。所以注意使用该方法的前提是AOP的动态代理使用的cglib而不是JDK自带的动态代理。
cglib是支撑基于类的动态代理,而JDK自带的是基于接口的动态代理。 使用cglib配置 <aop:aspectj-autoproxy proxy-target-class="true"/>
2. 将@Transaction下沉到flow层。最简单也最合理。
3. 可先通过AOP的代理类获取原始类,再通过原始类去获取注解。
先判断是不是Advised的实例。所有AOP代理的类都可以转型为Advised接口,可通过它找到原始类。 instanceof Advised。通过 getTargetSource() getTarget() getClass() 获取到原始类。https://blog.csdn.net/u011403655/article/details/52259566
由此可见虽然只在一个方法上加了@Transaction注解,但整个类都会被AOP代理。
为什么只有加@Transaction注解使自定义注解失效,而原先方法上的其他注解却没有影响到自定义注解?
@Transaction使用的是AOP的动态代理生成的代理类,其他注解不是AOP。
常见的AOP注解如:@Aspect,@Before,@After,@Around,@Transaction。
若将@Transaction放到其他类如Controller的方法上,原始类的其他注解如@GetMapping并没有失效,功能正常。是否不用getAnnotation就不影响注解的功能?
以上是关于@Transactional使自定义注解失效的主要内容,如果未能解决你的问题,请参考以下文章
springboot+springcache+shiro+Redis整合时@Cacheable@Transactional等注解失效的问题
(转载)@Transactional spring 事务失效