【问题标题】:Is it safe to use a Spring @Transactional annotation on a Java 8 default interface method?在 Java 8 默认接口方法上使用 Spring @Transactional 注释是否安全?
【发布时间】:2013-12-25 23:48:09
【问题描述】:

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

这会起作用吗(即在这种情况下,spring 会尊重事务边界)吗?如果是这样,这种方法是否有任何隐藏的陷阱?

【问题讨论】:

  • 如果你需要一个方法的默认实现,为什么不创建一个抽象类而不是一个接口呢? Java 8 API 文档让我相信接口默认方法主要是为了允许向接口添加新方法,而不会破坏该接口的旧实现。
  • 接口默认方法允许您创建mixins,这是一个比传统java接口更强大的编程结构。是否有正当理由在事务接口中使用 mixin 是另一个问题,但这并非不可想象。使用抽象类也可以,但会将您限制在线性对象层次结构中。 Mixin 更加灵活。

标签: java spring transactions annotations java-8


【解决方案1】:

在为使用@Transactional 注释的类或包含使用@Transactional 注释的方法生成代理bean 时,Spring 使用(以及其他)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()

表示该注解是为接口的方法继承的。因此,当类没有覆盖 default 方法时,Spring 似乎能够添加 @Transactional 行为。如果它已覆盖它,则注释不会被继承。

【讨论】:

  • 非常好的测试。更进一步,您可以覆盖 RandomImpl 中的默认实现,并演示您必须将注释放在覆盖方法上才能看到它。我认为这与使用继承没有什么不同。
  • @JMB 对,我是在本地完成的,但没有在此处发布示例。最后一句涵盖了它。等我回家再补充。
猜你喜欢
  • 2015-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
  • 2015-04-25
  • 2018-02-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多