Kho lưu trữ Dữ liệu Mùa xuân thực sự được triển khai như thế nào?


111

Tôi đã làm việc với kho lưu trữ Spring Data JPA trong dự án của mình một thời gian và tôi biết những điểm dưới đây:

  • Trong các giao diện kho lưu trữ, chúng ta có thể thêm các phương thức như findByCustomerNameAndPhone()(giả sử customerNamephonelà các trường trong đối tượng miền).
  • Sau đó, Spring cung cấp việc triển khai bằng cách triển khai các phương thức giao diện kho lưu trữ ở trên trong thời gian chạy (trong quá trình chạy ứng dụng).

Tôi quan tâm đến cách mã này được mã hóa và tôi đã xem mã nguồn & API Spring JPA, nhưng tôi không thể tìm thấy câu trả lời cho các câu hỏi bên dưới:

  1. Lớp triển khai kho lưu trữ được tạo ra trong thời gian chạy và các phương thức được triển khai và đưa vào như thế nào?
  2. Spring Data JPA có sử dụng CGlib hoặc bất kỳ thư viện thao tác bytecode nào để triển khai các phương thức và chèn động không?

Bạn có thể vui lòng trợ giúp với các truy vấn trên và cung cấp bất kỳ tài liệu hỗ trợ nào không?

Câu trả lời:


144

Trước hết, không có quá trình tạo mã nào diễn ra, có nghĩa là: không có CGLib, không có quá trình tạo mã byte. Cách tiếp cận cơ bản là một phiên bản proxy JDK được tạo theo chương trình bằng cách sử dụng ProxyFactoryAPI của Spring để quay lại giao diện và MethodInterceptorchặn tất cả các lệnh gọi đến phiên bản và định tuyến phương thức đến những vị trí thích hợp:

  1. Nếu kho lưu trữ đã được khởi tạo với một phần triển khai tùy chỉnh (xem phần đó của tài liệu tham khảo để biết chi tiết) và phương thức được gọi được thực hiện trong lớp đó, thì lệnh gọi sẽ được chuyển đến đó.
  2. Nếu phương thức là một phương thức truy vấn (xem DefaultRepositoryInformationcách xác định điều đó), cơ chế thực thi truy vấn cụ thể của cửa hàng sẽ khởi động và thực thi truy vấn được xác định sẽ được thực thi cho phương thức đó khi khởi động. Vì vậy, một cơ chế phân giải được đặt ra để cố gắng xác định các truy vấn được khai báo rõ ràng ở nhiều nơi khác nhau (sử dụng @Querytrên phương thức, các truy vấn có tên JPA) cuối cùng quay trở lại truy vấn dẫn xuất từ ​​tên phương thức. Để phát hiện cơ chế truy vấn, hãy xem JpaQueryLookupStrategy. Bạn có thể tìm thấy lôgic phân tích cú pháp cho dẫn xuất truy vấn trong PartTree. Bản dịch cụ thể của cửa hàng thành một truy vấn thực tế có thể được nhìn thấy, ví dụ: trong JpaQueryCreator.
  3. Nếu không có cách nào ở trên áp dụng, phương thức được thực thi phải được thực thi bởi một lớp cơ sở kho lưu trữ cụ thể cho cửa hàng ( SimpleJpaRepositorytrong trường hợp JPA) và cuộc gọi được chuyển đến một thể hiện của phương thức đó.

Phương thức đánh chặn thực hiện logic định tuyến đó là logic định tuyến QueryExecutorMethodInterceptormức cao có thể được tìm thấy tại đây .

Việc tạo ra các proxy đó được gói gọn trong một triển khai mẫu Factory dựa trên Java tiêu chuẩn. Tạo proxy cấp cao có thể được tìm thấy trong RepositoryFactorySupport. Sau đó, các triển khai dành riêng cho cửa hàng sẽ thêm các thành phần cơ sở hạ tầng cần thiết để đối với JPA, bạn có thể tiếp tục và chỉ cần viết mã như sau:

EntityManager em =  // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);

Lý do tôi đề cập đến điều đó một cách rõ ràng là cần phải nói rõ rằng, trong cốt lõi của nó, không có gì trong mã đó yêu cầu một vùng chứa Spring để chạy ngay từ đầu. Nó cần Spring như một thư viện trên classpath (vì chúng tôi không muốn phát minh lại bánh xe), nhưng nói chung là container bất khả tri.

Để dễ dàng tích hợp với các vùng chứa DI, tất nhiên, sau đó chúng tôi đã xây dựng tích hợp với cấu hình Spring Java, không gian tên XML, nhưng cũng có một phần mở rộng CDI , để Dữ liệu mùa xuân có thể được sử dụng trong các kịch bản CDI thuần túy.


3
Xin chào Oliver, bạn có thể giải thích chi tiết về cách mùa xuân phát hiện ra các @Repositorygiao diện được chú thích ngay từ đầu không? Nhìn vào RepositoryFactorySupport#getRepository()cho thấy rằng nó lấy lớp giao diện làm tham số, vì vậy nó phải được phát hiện ở một nơi khác. Tôi đặc biệt đang cố gắng tìm ra cách tìm một giao diện có chú thích và tự động tạo một bean proxy JDK triển khai giao diện, rất giống với dữ liệu mùa xuân, nhưng cho mục đích ứng dụng cụ thể không liên quan đến Kho lưu trữ.
Chris Rice

1
Bạn có thể muốn xem qua RepositoryComponentProvider. Không có điều tự động nào xảy ra ngoài việc quét thành phần cho một số loại nhất định (có chú thích hoặc mang chú thích) và FactoryBeanđịnh cấu hình cho từng loại đó.
Oliver Drotbohm

2
Xin lỗi khi nhận xét về một chủ đề cũ, nhưng rất tò mò ... Các proxy của kho lưu trữ có phải là các đối tượng singleton không? Chúng tôi đang gặp sự cố trong đó mã của chúng tôi đang cố gắng gọi một phương thức repo, nhưng dường như nó không bao giờ có thể thực hiện cuộc gọi trên proxy. Nó chỉ bị treo. Tôi tự hỏi liệu nó có đang chờ một singleton bận rộn không.
iu.david
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.