2013-12-09 23 views
12

Tài liệu Spring khuyến cáo không nên đặt chú thích @Transactional trên các phương thức giao diện vì chú thích giao diện không được kế thừa bởi các lớp. Tuy nhiên, với Java 8, chúng tôi có thể cung cấp triển khai mặc định cụ thể trong giao diện. Nếu phương thức giao diện mặc định như vậy cần phải là ranh giới giao dịch, chúng tôi không có lựa chọn nào khác: chúng tôi phải đặt chú thích @Transactional trên phương thức giao diện.Có an toàn khi sử dụng chú thích Spring @Transactional trên phương thức giao diện mặc định Java 8 không?

Tác vụ này có hoạt động (tức là mùa xuân sẽ tôn trọng ranh giới giao dịch trong trường hợp này)? Nếu vậy, có bất kỳ cạm bẫy tiềm ẩn nào cho phương pháp này không?

+0

Nếu bạn cần cài đặt mặc định phương thức, tại sao không tạo lớp trừu tượng thay vì giao diện? Các tài liệu API Java 8 dẫn tôi tin rằng các phương thức mặc định của giao diện chủ yếu nhằm cho phép bổ sung các phương thức mới vào một giao diện mà không phá vỡ các triển khai cũ hơn của giao diện đó. – VGR

+0

Các phương thức mặc định của giao diện cho phép bạn tạo [mixins] (https://en.wikipedia.org/wiki/Mixin), đây là một cấu trúc lập trình mạnh hơn nhiều so với các giao diện java truyền thống. Cho dù có một lý do hợp lệ để sử dụng mixin trong giao diện Dịch vụ với Giao dịch là một vấn đề khác, nhưng nó không phải là không thể tưởng tượng được. Sử dụng các lớp trừu tượng cũng sẽ làm việc, nhưng ràng buộc bạn với một hệ thống phân cấp đối tượng tuyến tính. Mixins linh hoạt hơn nhiều. – JMB

Trả lời

10

Sử dụng mùa xuân (trong số những người khác) là BeanFactoryTransactionAttributeSourceAdvisor là một Advisor khi tạo bean proxy cho các lớp được chú thích hoặc chứa phương pháp được chú thích với @Transactional.

Khi thời gian đến proxy, nó sử dụng loại lớp của bean (với CGLIB) để tạo proxy. Vì vậy, chúng tôi muốn xem phương thức default được chú thích với @Transactional sẽ hiển thị từ quan điểm của lớp triển khai hay không.

Dưới đây là một 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 {} 

mà in

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

chỉ ra rằng chú thích được thừa hưởng cho phương pháp của giao diện. Có vẻ như, do đó, Spring sẽ có thể thêm hành vi @Transactional khi lớp học không ghi đè phương thức default. Nếu nó đã overriden nó, sau đó chú thích không được thừa hưởng.

+0

Kiểm tra rất đẹp. Để tiến xa hơn một bước, bạn có thể ghi đè việc triển khai mặc định trong RandomImpl và chứng minh rằng bạn phải đặt chú thích trên phương thức ghi đè để có thể nhìn thấy nó. Tôi không tin rằng điều này là khác nhau từ việc sử dụng thừa kế. – JMB

+0

@JMB Phải, tôi đã làm nó tại địa phương, nhưng không đăng ví dụ ở đây. Câu cuối cùng bao gồm nó. Tôi sẽ thêm nó khi tôi về nhà sau. –

Các vấn đề liên quan