Erstens findet keine Codegenerierung statt, was bedeutet: keine CGLib, überhaupt keine Bytecodegenerierung. Der grundlegende Ansatz besteht darin, dass eine JDK-Proxy-Instanz mithilfe der Spring- ProxyFactory
API programmgesteuert erstellt wird , um die Schnittstelle zu sichern, und MethodInterceptor
alle Aufrufe der Instanz abfängt und die Methode an die entsprechenden Stellen weiterleitet:
- Wenn das Repository mit einem benutzerdefinierten Implementierungsteil initialisiert wurde ( Einzelheiten finden Sie in diesem Teil der Referenzdokumentation ) und die aufgerufene Methode in dieser Klasse implementiert ist, wird der Aufruf dort weitergeleitet.
- Wenn es sich bei der Methode um eine Abfragemethode handelt (siehe dies
DefaultRepositoryInformation
), wird der speicherspezifische Abfrageausführungsmechanismus aktiviert und führt die Abfrage aus, die beim Start für diese Methode ausgeführt werden soll. Zu diesem Zweck ist ein Auflösungsmechanismus vorhanden, der versucht, explizit deklarierte Abfragen an verschiedenen Stellen zu identifizieren (unter Verwendung @Query
von JPA-benannten Abfragen für die Methode), die schließlich auf die Ableitungsableitung aus dem Methodennamen zurückgreifen. Informationen zur Erkennung des Abfragemechanismus finden Sie unter JpaQueryLookupStrategy
. Die Parsing-Logik für die Abfrage-Ableitung finden Sie in PartTree
. Die speicherspezifische Übersetzung in eine tatsächliche Abfrage ist zB in zu sehen JpaQueryCreator
.
- Wenn keine der oben genannten Methoden zutrifft, muss die ausgeführte Methode von einer speicherspezifischen Repository-Basisklasse (
SimpleJpaRepository
im Fall von JPA) implementiert werden, und der Aufruf wird an eine Instanz davon weitergeleitet.
Der Methoden-Interceptor, der diese Routing-Logik implementiert, ist QueryExecutorMethodInterceptor
die High-Level-Routing-Logik, die hier zu finden ist .
Die Erstellung dieser Proxys ist in einer standardmäßigen Java-basierten Factory-Musterimplementierung gekapselt. Die übergeordnete Proxy-Erstellung finden Sie in RepositoryFactorySupport
. Die speicherspezifischen Implementierungen fügen dann die erforderlichen Infrastrukturkomponenten hinzu, sodass Sie für JPA einfach Code wie folgt schreiben können:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
Der Grund, warum ich dies ausdrücklich erwähne, ist, dass klar werden sollte, dass für nichts von diesem Code ein Spring-Container erforderlich ist, um überhaupt ausgeführt zu werden. Es benötigt Spring als Bibliothek auf dem Klassenpfad (weil wir es vorziehen, das Rad nicht neu zu erfinden), ist aber im Allgemeinen containerunabhängig.
Um die Integration in DI-Container zu vereinfachen, haben wir dann natürlich die Integration mit der Spring Java-Konfiguration erstellt, einem XML-Namespace, aber auch einer CDI-Erweiterung , damit Spring Data in einfachen CDI-Szenarien verwendet werden kann.
@Repository
kommentierten Schnittstellen überhaupt entdeckt ? Ein Blick aufRepositoryFactorySupport#getRepository()
zeigt, dass die Schnittstellenklasse als Parameter verwendet wird, sodass sie an einer anderen Stelle gefunden werden muss. Ich versuche insbesondere herauszufinden, wie eine mit Anmerkungen versehene Schnittstelle gefunden und automatisch eine JDK-Proxy-Bean generiert wird, die die Schnittstelle ähnlich wie Spring-Daten implementiert, jedoch für einen anwendungsspezifischen Zweck, der nicht mit Repositorys zusammenhängt.RepositoryComponentProvider
. Es passieren keine automatischen Ereignisse, sondern ein Komponentenscan für bestimmte Typen (entweder mit Anmerkungen versehen oder mit Anmerkungen versehen) und eineFactoryBean
für jeden dieser Typen konfigurierte.