it-swarm.com.de

Wie werden Spring Data-Repositorys tatsächlich implementiert?

Ich arbeite in meinem Projekt seit einiger Zeit mit dem JPA-Repository von Spring Data und kenne die folgenden Punkte:

  • In den Repository-Schnittstellen können wir Methoden wie findByCustomerNameAndPhone() hinzufügen (vorausgesetzt, customerName und phone sind Felder im Domänenobjekt).
  • Anschließend stellt Spring die Implementierung bereit, indem die obigen Repository-Schnittstellenmethoden zur Laufzeit (während des Anwendungslaufs) implementiert werden.

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:

  1. Wie wird die zur Laufzeit generierte Repository-Implementierungsklasse & Methoden implementiert und injiziert?
  2. Verwendet Spring Data JPA CGlib oder Bytecode-Manipulationsbibliotheken, um die Methoden zu implementieren und dynamisch zu injizieren?

Können Sie uns bitte bei den oben genannten Fragen helfen und unterstützte Unterlagen zur Verfügung stellen?

87
developer

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:

  1. Wenn das Repository mit einem benutzerdefinierten Implementierungsteil initialisiert wurde (siehe dieser Teil der Referenzdokumentation für Details) und die aufgerufene Methode in dieser Klasse implementiert ist, wird der Aufruf dorthin weitergeleitet.
  2. Wenn es sich bei der Methode um eine Abfragemethode handelt (siehe 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 .
  3. Wenn keine der oben genannten Bedingungen zutrifft, muss die ausgeführte Methode eine sein, die von einer geschäftsspezifischen Repository-Basisklasse implementiert wurde ( 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.

113
Oliver Drotbohm