在 Java 8 默认接口方法上使用 Spring @Transactional 注释是否安全?

2022-09-02 13:46:17

Spring 文档建议不要在接口方法上放置@Transactional注释,因为类不会继承接口注释。但是,在Java 8中,我们可以在接口中提供具体的默认实现。如果这样的默认接口方法需要作为事务边界,我们别无选择:我们必须在接口方法上放置@Transactional注释。

这是否有效(即在这种情况下,弹簧会尊重交易边界)?如果是这样,这种方法是否有任何隐藏的陷阱?


答案 1

Spring 使用 (以及其他) a 作为为使用 注释或包含带有 注释的方法的类生成代理 Bean 时。BeanFactoryTransactionAttributeSourceAdvisorAdvisor@Transactional

当需要代理它时,它使用Bean的类类型(使用CGLIB)来生成代理。因此,我们想要看看从实现类的角度来看,注释的方法是否可见。default@Transactional

这是一个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似乎能够添加行为。如果它已覆盖它,则不会继承批注。@Transactionaldefault


答案 2

推荐