Wie werden Spring Data Repositories eigentlich implementiert?

Lesezeit: 3 Minuten

Wie werden Spring Data Repositories eigentlich implementiert
Entwickler

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

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

Ich interessiere mich dafür, wie dies codiert wurde, und habe mir den Quellcode und die APIs von Spring JPA angesehen, aber ich konnte keine Antworten auf die folgenden Fragen finden:

  1. Wie wird die Repository-Implementierungsklasse zur Laufzeit generiert und Methoden implementiert und injiziert?
  2. Verwendet Spring Data JPA CGlib oder irgendwelche Bytecode-Manipulationsbibliotheken, um die Methoden zu implementieren und dynamisch einzufügen?

Könnten Sie bitte bei den obigen Fragen helfen und auch unterstützte Dokumentation bereitstellen?

Wie werden Spring Data Repositories eigentlich implementiert
Oliver Drotbohm

Zunächst einmal findet keine Code-Generierung statt, was bedeutet: überhaupt keine CGLib, keine Byte-Code-Generierung. Der grundlegende Ansatz besteht darin, dass eine JDK-Proxy-Instanz programmgesteuert mit Spring erstellt wird ProxyFactory API zur Unterstützung der Schnittstelle und a MethodInterceptor fängt alle Aufrufe an die 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 geleitet.
  2. Wenn die Methode eine Abfragemethode ist (vgl DefaultRepositoryInformation wie das bestimmt wird), springt der geschäftsspezifische Abfrageausführungsmechanismus ein und führt die Abfrage aus, die bestimmt wurde, um für dieses Verfahren beim Start ausgeführt zu werden. Dafür gibt es einen Auflösungsmechanismus, der versucht, explizit deklarierte Abfragen an verschiedenen Stellen zu identifizieren (mittels @Query auf der Methode, JPA-benannte Abfragen) schließlich auf die Abfrageableitung aus dem Methodennamen zurückgreifen. Zur Erkennung des Abfragemechanismus siehe JpaQueryLookupStrategy. Die Parsing-Logik für die Abfrageableitung finden Sie in PartTree. Die filialspezifische Übersetzung in eine tatsächliche Abfrage ist z. B. in zu sehen JpaQueryCreator.
  3. Wenn keiner der oben genannten Punkte zutrifft, muss die ausgeführte Methode von einer geschäftsspezifischen Repository-Basisklasse implementiert werden (SimpleJpaRepository im Fall von JPA) und der Anruf wird in eine Instanz davon geleitet.

Der Methoden-Interceptor, der diese Routing-Logik implementiert, ist QueryExecutorMethodInterceptorkann die High-Level-Routing-Logik gefunden werden Hier.

Die Erstellung dieser Proxys ist in eine standardmäßige Java-basierte Factory-Pattern-Implementierung eingekapselt. Die High-Level-Proxy-Erstellung finden Sie in RepositoryFactorySupport. Die geschäftsspezifischen Implementierungen fügen dann die erforderlichen Infrastrukturkomponenten hinzu, sodass Sie für JPA fortfahren und einfach Code wie diesen 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 nichts von diesem Code im Kern erfordert, dass ein Spring-Container überhaupt ausgeführt wird. Es benötigt Spring als Bibliothek auf dem Klassenpfad (weil wir es vorziehen, das Rad nicht neu zu erfinden), ist aber im Allgemeinen Container-agnostisch.

Um die Integration mit DI-Containern zu erleichtern, haben wir dann natürlich eine Integration mit Spring Java-Konfiguration, einem XML-Namespace, aber auch einer CDI-Erweiterungsodass Spring Data in einfachen CDI-Szenarien verwendet werden kann.

  • Hallo Oliver, kannst du näher darauf eingehen, wie der Frühling das entdeckt @Repository überhaupt annotierte Schnittstellen? Anschauen RepositoryFactorySupport#getRepository() zeigen, dass es die Schnittstellenklasse als Parameter nimmt, also muss es woanders entdeckt werden. Ich versuche insbesondere herauszufinden, wie man eine annotierte Schnittstelle findet und automatisch eine JDK-Proxy-Bean generiert, die die Schnittstelle implementiert, ähnlich wie Spring-Data, aber für einen anwendungsspezifischen Zweck, der nicht mit Repositories zusammenhängt.

    – Chris Reis

    26. Juni 2017 um 21:10 Uhr

  • Vielleicht möchten Sie einen Blick darauf werfen RepositoryComponentProvider. Es passieren keine automatischen Dinge, sondern ein Komponenten-Scan für bestimmte Typen (entweder kommentiert oder mit einer Anmerkung versehen) und a FactoryBean für jeden von diesen konfiguriert.

    – Oliver Drotbohm

    23. November 2017 um 17:15 Uhr

  • Tut mir leid, einen alten Thread zu kommentieren, aber war neugierig … Sind die Repository-Proxys Singleton-Objekte? Wir sehen ein Problem, bei dem unser Code versucht, eine Repo-Methode aufzurufen, aber anscheinend nie in der Lage ist, den Aufruf auf dem Proxy durchzuführen. Es hängt einfach. Ich frage mich, ob es auf einen Singleton wartet, der beschäftigt ist.

    – iu.david

    15. Juni 2018 um 15:48 Uhr

868290cookie-checkWie werden Spring Data Repositories eigentlich implementiert?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy