Ich arbeite in meinem Projekt seit einiger Zeit mit dem JPA-Repository von Spring Data und kenne die folgenden Punkte:
findByCustomerNameAndPhone()
hinzufügen (vorausgesetzt, customerName
und phone
sind Felder im Domänenobjekt).Ich bin daran interessiert, wie dies codiert wurde, und habe mir den Spring JPA-Quellcode und die APIs angesehen, konnte jedoch keine Antworten auf die folgenden Fragen finden:
Können Sie uns bitte bei den oben genannten Fragen helfen und unterstützte Unterlagen zur Verfügung stellen?
Erstens findet keine Codegenerierung statt, was bedeutet: Keine CGLib, überhaupt keine Bytecode-Generierung. Der grundlegende Ansatz besteht darin, dass eine JDK-Proxy-Instanz programmgesteuert mithilfe der ProxyFactory
-API von Spring erstellt wird, um die Schnittstelle zu sichern. Ein MethodInterceptor
fängt alle Aufrufe der Instanz ab und leitet die Methode an die entsprechenden Stellen weiter:
DefaultRepositoryInformation
, um zu erfahren, wie diese ermittelt wird), wird der spezifische Mechanismus zur Ausführung von Abfragen aktiviert und die Abfrage ausgeführt, die beim Start für diese Methode ausgeführt werden soll . Dafür gibt es einen Auflösungsmechanismus, der versucht, explizit deklarierte Abfragen an verschiedenen Stellen zu identifizieren (mit @Query
für die Methode, JPA-benannte Abfragen), die schließlich auf die Abfrageableitung aus dem Methodennamen zurückgreifen. Informationen zur Erkennung von Abfragemechanismen finden Sie unter JpaQueryLookupStrategy
. Die Parsing-Logik für die Abfrageableitung finden Sie in PartTree
. Die speicherspezifische Übersetzung in eine tatsächliche Abfrage kann z.B. in JpaQueryCreator
.SimpleJpaRepository
im Fall von JPA), und der Aufruf wird an eine Instanz von weitergeleitet Das.Der Methoden-Interceptor, der diese Routing-Logik implementiert, ist QueryExecutorMethodInterceptor
, die High-Level-Routing-Logik kann gefunden werden hier .
Die Erstellung dieser Proxys ist in einer standardmäßigen Java) - basierten Factory-Musterimplementierung gekapselt. Die allgemeine Proxy-Erstellung finden Sie in RepositoryFactorySupport
Filialspezifische Implementierungen fügen dann die erforderlichen Infrastrukturkomponenten hinzu, sodass Sie für JPA den folgenden Code schreiben können:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
Der Grund, warum ich das ausdrücklich erwähne, ist, dass klar werden sollte, dass in seinem Kern nichts von diesem Code die Ausführung eines Spring-Containers an erster Stelle erfordert. Es braucht 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 mit DI-Containern zu vereinfachen, haben wir natürlich die Integration mit Spring Java configuration, ein XML-Namespace, aber auch ein CDI-Erweiterung , damit Spring Data erstellt kann in einfachen CDI-Szenarien verwendet werden.