1. ホーム
  2. java

[解決済み] Spring Dataのリポジトリは実際にどのように実装されているのでしょうか?

2022-06-01 10:37:22

質問

私は以前からプロジェクトでSpring Data JPAリポジトリを使っており、以下の点を知っています。

  • リポジトリインターフェースに、以下のようなメソッドを追加することができます。 findByCustomerNameAndPhone() (仮に customerNamephone はドメインオブジェクトのフィールドです)。
  • そして、Springは実行時(アプリケーション実行時)に上記のリポジトリインターフェースのメソッドを実装することで、実装を提供します。

私はこれがどのようにコーディングされたかに興味があり、Spring JPAのソースコードとAPIを見ましたが、以下の質問に対する回答は見つかりませんでした。

  1. リポジトリ実装クラスはどのように実行時に生成され、メソッドは実装され、注入されるのですか?
  2. Spring Data JPAでは、CGlibやバイトコード操作ライブラリを使ってメソッドを実装し、動的にインジェクトしているのでしょうか?

上記のクエリについて、サポートされているドキュメントを提供していただけませんか?

どのように解決するのですか?

まず、コード生成は行われません。つまり、CGLibもバイトコードも全く生成されないということです。基本的なアプローチは、JDKプロキシのインスタンスをプログラム的に作成することで、Springの ProxyFactory APIを使ってJDKプロキシインスタンスをプログラム的に作成し、インターフェイスをバックアップすることです。 MethodInterceptor はインスタンスへのすべての呼び出しをインターセプトし、 メソッドを適切な場所にルーティングします。

  1. リポジトリがカスタム実装部で初期化されている場合 ( リファレンスドキュメントのその部分 を参照)、呼び出されたメソッドがそのクラスで実装されている場合、呼び出しはそこにルーティングされます。
  2. メソッドがクエリメソッドである場合 ( DefaultRepositoryInformation を参照)、ストア固有のクエリ実行メカニズムが起動し、 起動時にそのメソッドに対して実行されることが決定されたクエリを実行します。そのために、様々な場所で明示的に宣言されたクエリを識別しようとする解決メカニズムがあります ( @Query を使用)、最終的にはメソッド名からクエリを派生させることになります。クエリメカニズムの検出については JpaQueryLookupStrategy . クエリ導出のためのパースロジックは PartTree . 店舗固有の実際のクエリへの変換は、例えば次のようになります。 JpaQueryCreator .
  3. 上記のいずれにも当てはまらない場合、実行されるメソッドは、店舗固有のリポジトリベースクラスによって実装されたものでなければなりません ( SimpleJpaRepository で実装されたものでなければならず、呼び出しはそのインスタンスにルーティングされます。

そのルーティングロジックを実装したメソッドインターセプターは QueryExecutorMethodInterceptor であり、上位のルーティングロジックは ここに .

これらのプロキシの作成は、標準的なJavaベースのFactoryパターンの実装にカプセル化されています。高レベルのプロキシ生成は、以下のサイトで見ることができます。 RepositoryFactorySupport . ストア固有の実装は、必要なインフラコンポーネントを追加し、JPAではこのようなコードを書くことができます。

EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);

このように明確に言及するのは、このコードの中核には、そもそも実行するためにSpringコンテナを必要とするものがないことが明らかになるためです。クラスパス上のライブラリとしてSpringが必要ですが(車輪の再発明は避けたいので)、一般的にはコンテナには依存しません。

DIコンテナとの統合を容易にするために、もちろんSpringのJava設定、XML名前空間、さらに CDI拡張 を追加し、Spring DataをCDIシナリオで使用できるようにしました。