私はしばらくの間、プロジェクトで Spring Data JPA リポジトリを使用してきましたが、以下の点を知っています。
- リポジトリ インターフェイスでは、次のようなメソッドを追加できます
findByCustomerNameAndPhone()
(およびはドメイン オブジェクト内のフィールドであるcustomerName
と想定します)。phone
- 次に、Spring は、実行時 (アプリケーションの実行中) に上記のリポジトリ インターフェース メソッドを実装することで実装を提供します。
私はこれがどのようにコード化されているかに興味があり、Spring JPA ソース コードと API を調べましたが、以下の質問に対する答えを見つけることができませんでした。
- リポジトリ実装クラスは実行時にどのように生成され、メソッドはどのように実装および注入されるのでしょうか?
- Spring Data JPA は、メソッドを実装して動的に挿入するために CGlib またはバイトコード操作ライブラリを使用しますか?
上記の質問についてご支援いただき、またサポートされているドキュメントも提供していただけますか?
ベストアンサー1
まず、コード生成は行われません。つまり、CGLib もバイトコード生成もまったく行われません。基本的なアプローチは、Spring のProxyFactory
API を使用してプログラム的に JDK プロキシ インスタンスを作成し、インターフェイスをサポートし、MethodInterceptor
インスタンスへのすべての呼び出しをインターセプトして、メソッドを適切な場所にルーティングすることです。
- リポジトリがカスタム実装部分で初期化されている場合(参照ドキュメントのその部分詳細については、こちらをご覧ください。呼び出されたメソッドがそのクラスに実装されている場合、呼び出しはそこにルーティングされます。
- メソッドがクエリメソッドの場合(
DefaultRepositoryInformation
どのように決定されるかは、ストア固有のクエリ実行メカニズムが起動し、起動時にそのメソッドに対して実行されるように決定されたクエリを実行します。そのために、さまざまな場所で明示的に宣言されたクエリを識別しようとする解決メカニズムが用意されています(@Query
メソッドで、JPA の名前付きクエリを使用)。最終的にはメソッド名からのクエリ派生に戻ります。クエリメカニズムの検出については、JpaQueryLookupStrategy
クエリ導出の解析ロジックについては、PartTree
店舗固有の実際のクエリへの翻訳は、例えば以下で確認できます。JpaQueryCreator
。 - 上記のいずれにも当てはまらない場合、実行されるメソッドはストア固有のリポジトリ基本クラスによって実装されたものでなければなりません(
SimpleJpaRepository
(JPA の場合)、呼び出しはそのインスタンスにルーティングされます。
そのルーティングロジックを実装するメソッドインターセプターはQueryExecutorMethodInterceptor
、高レベルのルーティングロジックは、ここ。
これらのプロキシの作成は、標準的なJavaベースのファクトリーパターン実装にカプセル化されています。高レベルのプロキシ作成は、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 シナリオで使用できるようになります。