简体   繁体   English

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

[英]Is it safe to use a Spring @Transactional annotation on a Java 8 default interface method?

The Spring documentation recommends against putting @Transactional annotations on interface methods because interface annotations are not inherited by classes. Spring文档建议不要在接口方法上放置@Transactional注释,因为接口注释不是由类继承的。 However, with Java 8 we can provide a concrete default implementation in the interface. 但是,使用Java 8,我们可以在界面中提供具体的默认实现。 If such a default interface method needs to be the transactional boundary, we have no other choice: we have to put the @Transactional annotation on the interface method. 如果这样的默认接口方法需要是事务边界,我们别无选择:我们必须在接口方法上放置@Transactional注释。

Will this work (ie will spring respect the transaction boundary in this case)? 这会起作用(即在这种情况下春天是否会尊重交易边界)? If so, are there any hidden pitfalls to this approach? 如果是这样,这种方法有任何隐藏的陷阱吗?

Spring uses (among others) a BeanFactoryTransactionAttributeSourceAdvisor as an Advisor when generating a proxy bean for classes annotated with or containing methods annotated with @Transactional . 在为使用@Transactional注释的方法注释或包含注释的类生成代理bean时,Spring使用(以及其他) BeanFactoryTransactionAttributeSourceAdvisor作为Advisor

When the time comes to proxy it, it uses the bean's class type (with CGLIB) to generate the proxy. 当需要代理它时,它使用bean的类类型(使用CGLIB)来生成代理。 So we want to see if the default method annotated with @Transactional will be visible from the implementing class' point of view. 因此,我们希望看看从实现类的角度来看,使用@Transactional注释的default方法是否可见。

Here's a Java 8 SSCCE 这是一个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 {}

which prints 打印

class TestEnhancer$RandomImpl
Class: class TestEnhancer$RandomImpl
Class Annotation: null
Method: public default void TestEnhancer$Random.doRandom()
Method Annotation: @TestEnhancer$Easy()

Indicating that the annotation was inherited for the interface's method. 指示为接口的方法继承了注释。 It seems, therefore, that Spring will be able to add @Transactional behavior when the class has not overriden the default method. 因此,当类没有覆盖default方法时,Spring似乎能够添加@Transactional行为。 If it has overriden it, then annotations are not inherited. 如果它已覆盖它,则不会继承注释。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM