Як реально реалізовані сховища даних 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.