Можно ли использовать аннотацию Spring @Transactional в методе интерфейса по умолчанию Java 8?

Документация Spring рекомендует запретить аннотации @Transactional методов интерфейса, поскольку аннотации интерфейсов не наследуются классами. Однако с помощью Java 8 мы можем обеспечить конкретную реализацию по умолчанию в интерфейсе. Если такой метод интерфейса по умолчанию должен быть границей транзакций, у нас нет другого выбора: мы должны поместить аннотацию @Transactional в метод интерфейса.

Будет ли эта работа (т.е. будет Spring соблюдать границу транзакции в этом случае)? Если да, есть ли скрытые подводные камни для этого подхода?

Ответ 1

Spring использует (среди прочих) a BeanFactoryTransactionAttributeSourceAdvisor как Advisor при создании прокси bean для классов, аннотированных или содержащих методы, аннотированные с помощью @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 сможет добавить поведение @Transactional, когда класс не переопределит метод default. Если он ее преодолел, аннотации не наследуются.