Spring文档建议不要在接口方法上放置@Transactional注释,因为接口注释不会被类继承。但是,在Java 8中,我们可以在接口中提供具体的默认实现。如果这样的默认接口方法需要成为事务边界,我们别无选择:必须在接口方法上放置@Transactional注释。
这种情况下,这样做是否有效(即Spring是否会尊重事务边界)?如果是,则存在任何隐藏的缺陷吗?
Spring文档建议不要在接口方法上放置@Transactional注释,因为接口注释不会被类继承。但是,在Java 8中,我们可以在接口中提供具体的默认实现。如果这样的默认接口方法需要成为事务边界,我们别无选择:必须在接口方法上放置@Transactional注释。
这种情况下,这样做是否有效(即Spring是否会尊重事务边界)?如果是,则存在任何隐藏的缺陷吗?
Spring在生成带有或包含使用@Transactional
注解的方法的类的代理bean时,使用(其中之一)BeanFactoryTransactionAttributeSourceAdvisor
作为Advisor
。
当代理它的时候,它使用bean的类类型(使用CGLIB)来生成代理。因此,我们想确定从实现类的角度是否可以看到带有@Transactional
注解的default
方法。
这里是一个Java 8的SSCCE示例。
public static void main(String[] args) throws Exception{
Class<?> randomImplClass = RandomImpl.class;
System.out.println(randomImplClass);
Easy annotation = randomImplClass.getAnnotation(Easy.class);
System.out.println("Class: " + randomImplClass);
System.out.println("Class Annotation: " + annotation);
Method method = randomImplClass.getMethod("doRandom");
annotation = method.getAnnotation(Easy.class);
System.out.println("Method: " + method);
System.out.println("Method Annotation: " + annotation);
}
public static class RandomImpl implements Random{}
@Easy
interface Random {
@Easy
default void doRandom() {System.out.println("testing");};
}
@Target(value = {METHOD, TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Easy {}
打印输出
class TestEnhancer$RandomImpl
Class: class TestEnhancer$RandomImpl
Class Annotation: null
Method: public default void TestEnhancer$Random.doRandom()
Method Annotation: @TestEnhancer$Easy()
表示该注解是从接口的方法继承而来。因此,似乎当类没有覆盖默认方法时,Spring 将能够添加 @Transactional 行为。如果它已经覆盖了默认方法,则注解不会被继承。