Як реально реалізовані сховища даних Data?


111

Я працюю зі сховищем Spring Data JPA у своєму проекті вже деякий час, і мені відомо наступні моменти:

  • У інтерфейси сховища ми можемо додати такі методи, як findByCustomerNameAndPhone()(припускаючи customerNameта phoneє полями в об’єкті домену).
  • Потім Spring забезпечує реалізацію, реалізуючи вищезазначені методи інтерфейсу сховища під час виконання (під час запуску програми).

Мене цікавить, як це було закодовано, і я переглянув джерельний код і API Spring JPA, але не зміг знайти відповіді на наведені нижче запитання:

  1. Як створюється і вводиться клас впровадження репозиторію під час виконання та методи?
  2. Чи використовує Spring Data JPA використання CGlib або будь-які бібліотеки маніпуляцій з байт-кодом для впровадження методів та динамічно вводити їх?

Чи можете ви допомогти з вищезазначеними запитами, а також надати будь-яку підтримувану документацію?

Відповіді:


144

Перш за все, не відбувається генерація коду, а це означає: немає CGLib, взагалі немає генерації байт-кодів. Фундаментальний підхід полягає в тому, що проксі-екземпляр JDK створюється програмно за допомогою ProxyFactoryAPI Spring для резервного інтерфейсу та MethodInterceptorперехоплює всі виклики до екземпляра та спрямовує метод у відповідні місця:

  1. Якщо репозиторій був ініціалізований за допомогою спеціальної частини реалізації (детальніше див. Цю частину довідкової документації ), а метод, що викликається, реалізований у цьому класі, виклик направляється туди.
  2. Якщо метод є методом запиту (див. DefaultRepositoryInformationЯк це визначено), механізм виконання специфічного запиту заповнює і виконує запит, визначений для виконання цього методу при запуску. Для цього існує механізм роздільної здатності, який намагається ідентифікувати явно оголошені запити в різних місцях (використовуючи @Queryметод, JPA з іменами запитів), врешті повертаючись до виведення запиту з імені методу. Про механізм виявлення запиту див JpaQueryLookupStrategy. Логіку розбору для виведення запиту можна знайти в PartTree. Переклад конкретного магазину на фактичний запит можна побачити, наприклад, у JpaQueryCreator.
  3. Якщо нічого із зазначеного вище не застосовується, виконаний метод повинен бути таким, який реалізований базовим класом сховища для конкретного магазину ( SimpleJpaRepositoryу випадку JPA), і виклик перетворюється на екземпляр цього.

Метод перехоплювача, що реалізує цю логіку маршрутизації QueryExecutorMethodInterceptor, тут може бути знайдений логікою маршрутизації високого рівня .

Створення цих проксі-серверів інкапсульовано у стандартну реалізацію шаблону на основі Java. Створення проксі-серверів високого рівня можна знайти в RepositoryFactorySupport. Потім для конкретних магазинів реалізації додають необхідні компоненти інфраструктури, щоб у JPA можна було продовжувати та просто писати код так:

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

Причина, яку я прямо згадую, полягає в тому, що має стати зрозумілим, що, по суті, ніщо з цього коду не вимагає, щоб в першу чергу запускався контейнер Spring. Він потрібен Spring як бібліотека на шляху (тому що ми вважаємо за краще не винаходити колесо), але загалом є контейнерним агностиком.

Щоб полегшити інтеграцію з контейнерами DI, ми, звичайно, потім побудували інтеграцію з конфігурацією Spring Java, простором імен XML, а також розширенням CDI , щоб Spring Data можна було використовувати в звичайних сценаріях CDI.


3
Привіт Олівер, чи можеш ти детальніше розглянути, як весна виявляє @Repositoryспочатку помічені інтерфейси? Дивлячись на RepositoryFactorySupport#getRepository()показ, що він приймає клас інтерфейсу як параметр, тому його треба виявити десь ще. Я особливо намагаюся розібратися, як знайти анотований інтерфейс і автоматично генерувати проксі-сервер JDK, який реалізує інтерфейс, дуже схожий на весняні дані, але для конкретної програми, не пов'язаної з Репозиторіями.
— Кріс Райс

1
Ви можете поглянути на RepositoryComponentProvider. Нічого не відбувається автоматичного пошуку, але сканування компонентів для певних типів (або з анотацією, або з анотацією) та FactoryBeanналаштоване для кожного з них.
— Олівер Дротбом

2
Вибачте, що прокоментував старий потік, але було цікаво ... Чи є проксі-сервери сховища одиночними об’єктами? Ми бачимо проблему, згідно з якою наш код намагається викликати метод repo, але, схоже, він ніколи не може здійснити виклик на проксі. Це просто висить. Цікаво, чи чекає він сингла, який зайнятий.
— iu.david
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.