版权声明
- 本文原创作者:谷哥的小弟
- 作者博客地址:http://blog.csdn.net/lfdfhl
动态代理回顾
Spring的声明式事务管理是建立在 AOP 的基础之上的。Spring AOP是通过动态代理实现的。如果代理对象实现了接口,则使用JDK的动态代理;反之则使用cglib的动态代理。
@Transactional的使用细节
@Transactional注解可以作用于接口、接口方法、类以及类方法上。一般情况下,@Transactional注解使用在类上或类中的方法上;或者是接口上或接口中方法上,都可以实现事务功能。不过,有个细节问题需要注意,我们来看看官方文档的描述:
Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited from interfaces means that if you are using class-based proxies ( proxy-target-class=“true”) or the weaving-based aspect ( mode=“aspectj”), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a transactional proxy, which would be decidedly bad.
官方文档地址:https://docs.spring.io/spring-framework/docs/5.0.x/spring-framework-reference/data-access.html#transaction-declarative-annotations
Spring官方建议在类或类中的方法上使用@Transactional注解,而不是在接口或接口中的方法上使用。
在Java中,当你创建一个注解(比如@Transactional)并将其应用于某个接口或接口的方法上时,这个注解并不会自动被该接口的实现类继承。注解的继承行为与普通的Java类和接口继承不同。这意味着,仅仅在接口上放置注解并不足以确保所有实现该接口的类都会获得该注解所声明的行为(例如该示例中的事务管理)。
Spring框架提供了两种主要的动态代理机制来增强类的功能,比如添加事务管理:
- 1、基于接口的动态代理:Spring默认使用JDK的动态代理,它要求被代理的对象至少实现一个接口。在这种情况下,Spring会创建一个实现了相同接口的代理对象,并将调用委托给原始对象,同时在调用前后添加额外的逻辑(如事务管理)。如果@Transactional注解被应用在接口或接口方法上,并且你使用的是这种代理方式,那么注解会被代理机制识别,事务管理会正常工作。
- 2、基于类的动态代理:如果目标类没有实现接口,或者你在配置中显式指定了proxy-target-class=“true”,Spring会使用CGLIB库来创建一个目标类的子类作为代理。这个子类会重写父类的方法,并在重写的方法中添加额外的逻辑。但是,由于Java注解不是从接口继承到实现类的,如果你将@Transactional注解放在接口上,而你的代理是基于类的(即使用CGLIB),那么这个注解将不会被代理机制识别,因此事务管理不会生效。
AspectJ的织入方式是另一种增强类功能的机制,它可以在编译时、加载时或运行时将额外的逻辑织入到类中。与基于类的动态代理类似,如果@Transactional注解仅被应用在接口上,而你的项目使用的是AspectJ织入,那么这个注解同样不会被识别,因为它不会从接口传递到具体的类。
所以,为了确保@Transactional注解能够按预期工作,无论你的项目使用哪种代理或织入方式,最佳实践是将这个注解直接应用在具体的类或其方法上,而不是接口或接口方法上。这样可以避免由于注解不被识别而导致的事务管理失效的问题。