Ответ 1
Прежде всего, генерации кода не происходит, что означает: нет CGLib, без генерации байтового кода. Фундаментальный подход заключается в том, что экземпляр прокси-сервера JDK создается программно с использованием API Spring ProxyFactory
для поддержки интерфейса, а MethodInterceptor
перехватывает все вызовы экземпляра и направляет метод в соответствующие места:
- Если репозиторий был инициализирован с помощью специальной части реализации (см. эту часть справочной документации для получения подробной информации), а вызванный метод реализованный в этом классе, вызов маршрутизируется там.
- Если метод является методом запроса (см.
DefaultRepositoryInformation
для определения того, как это определено), механизм выполнения конкретных запросов магазина запускается и выполняет запуск запроса для этого метода при запуске. Для этого существует механизм разрешения, который пытается идентифицировать явно объявленные запросы в разных местах (используя@Query
в методе, JPA с именем запросов), в конце концов, возвращается к выводу запроса из имени метода. Для обнаружения механизма запроса см.JpaQueryLookupStrategy
. Логику синтаксического анализа для вывода запроса можно найти вPartTree
. Конкретный перевод хранилища в фактический запрос можно увидеть, например. вJpaQueryCreator
. - Если ни одно из вышеприведенных действий не применяется, выполненный метод должен быть реализован базовым классом репозитория, определенным хранилищем (
SimpleJpaRepository
в случае JPA), и вызов направляется в экземпляр этого.
Метод-перехватчик, реализующий эту логику маршрутизации, QueryExecutorMethodInterceptor
, логику маршрутизации высокого уровня можно найти здесь.
Создание этих прокси-объектов инкапсулируется в стандартную реализацию шаблона Factory на основе Java. Создание прокси-сервера высокого уровня можно найти в RepositoryFactorySupport
. Затем реализация хранилища добавляет необходимые компоненты инфраструктуры, поэтому для JPA вы можете продолжать писать и писать такой код:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
Причина, по которой я упоминаю, что явно заключается в том, что должно стать ясно, что в ее основе ничто из этого кода не требует, чтобы контейнер Spring запускался в первую очередь. Он нуждается в Spring в качестве библиотеки на пути к классам (потому что мы предпочитаем не изобретать колесо), но в целом не является агностиком контейнера.
Чтобы упростить интеграцию с контейнерами DI, мы, конечно же, построили интеграцию с конфигурацией Java Spring, пространство имен XML, а также расширение CDI, так что Spring Данные могут использоваться в простых сценариях CDI.