Spring Data 存储库是如何实际实现的? [英] How are Spring Data repositories actually implemented?

查看:24
本文介绍了Spring Data 存储库是如何实际实现的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在我的项目中使用 Spring Data JPA 存储库有一段时间了,我知道以下几点:

I have been working with Spring Data JPA repository in my project for some time and I know the below points:

  • 在存储库接口中,我们可以添加诸如 findByCustomerNameAndPhone() 之类的方法(假设 customerNamephone 是域对象中的字段).
  • 然后,Spring 通过在运行时(在应用程序运行期间)实现上述存储库接口方法来提供实现.
  • In the repository interfaces, we can add the methods like findByCustomerNameAndPhone() (assuming customerName and phone are fields in the domain object).
  • Then, Spring provides the implementation by implementing the above repository interface methods at runtime (during the application run).

我对它的编码方式很感兴趣,我查看了 Spring JPA 源代码 &API,但我找不到以下问题的答案:

I am interested on how this has been coded and I have looked at the Spring JPA source code & APIs, but I could not find answers to the questions below:

  1. repository 实现类是如何在运行时生成的 &正在实施和注入的方法?
  2. Spring Data JPA 是否使用 CGlib 或任何字节码操作库来实现方法并动态注入?

能否请您帮助解决上述问题并提供任何支持的文档?

Could you please help with the above queries and also provide any supported documentation ?

推荐答案

首先,没有代码生成,这意味着:没有 CGLib,根本没有字节码生成.基本方法是使用 Spring 的 ProxyFactory API 以编程方式创建 JDK 代理实例以支持接口,MethodInterceptor 拦截对实例的所有调用并将方法路由到适当的地点:

First of all, there's no code generation going on, which means: no CGLib, no byte-code generation at all. The fundamental approach is that a JDK proxy instance is created programmatically using Spring's ProxyFactory API to back the interface and a MethodInterceptor intercepts all calls to the instance and routes the method into the appropriate places:

  1. 如果存储库已使用自定义实现部分初始化(请参阅 参考文档的那部分了解详细信息),并且调用的方法在该类中实现,调用被路由到那里.
  2. 如果方法是查询方法(参见DefaultRepositoryInformation 了解如何确定),商店特定的查询执行机制启动并执行确定要在启动时为该方法执行的查询.为此,存在一种解析机制,该机制试图识别在不同位置显式声明的查询(在方法上使用 @Query,JPA 命名查询),最终回退到从方法名称派生的查询.查询机制检测参见JpaQueryLookupStrategy.查询推导的解析逻辑可以在PartTree.可以看到商店特定转换为实际查询,例如在 JpaQueryCreator.
  3. 如果以上都不适用,则执行的方法必须是由特定于商店的存储库基类实现的方法 (SimpleJpaRepositoryJPA 的情况)并且调用被路由到它的一个实例中.
  1. If the repository has been initialized with a custom implementation part (see that part of the reference documentation for details), and the method invoked is implemented in that class, the call is routed there.
  2. If the method is a query method (see DefaultRepositoryInformation for how that is determined), the store specific query execution mechanism kicks in and executes the query determined to be executed for that method at startup. For that a resolution mechanism is in place that tries to identify explicitly declared queries in various places (using @Query on the method, JPA named queries) eventually falling back to query derivation from the method name. For the query mechanism detection, see JpaQueryLookupStrategy. The parsing logic for the query derivation can be found in PartTree. The store specific translation into an actual query can be seen e.g. in JpaQueryCreator.
  3. If none of the above apply the method executed has to be one implemented by a store-specific repository base class (SimpleJpaRepository in case of JPA) and the call is routed into an instance of that.

实现路由逻辑的方法拦截器是QueryExecutorMethodInterceptor,高级路由逻辑见这里.

The method interceptor implementing that routing logic is QueryExecutorMethodInterceptor, the high level routing logic can be found here.

这些代理的创建被封装到一个标准的基于 Java 的工厂模式实现中.高级代理创建可以在 RepositoryFactorySupport.然后,特定于商店的实现添加必要的基础结构组件,以便对于 JPA,您可以继续编写如下代码:

The creation of those proxies is encapsulated into a standard Java based Factory pattern implementation. The high-level proxy creation can be found in RepositoryFactorySupport. The store-specific implementations then add the necessary infrastructure components so that for JPA you can go ahead and just write code like this:

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

我明确提到的原因是应该清楚,在其核心中,该代码的任何内容都不需要首先运行 Spring 容器.它需要 Spring 作为类路径上的库(因为我们不想重新发明轮子),但通常与容器无关.

The reason I mention that explicitly is that it should become clear that, in its core, nothing of that code requires a Spring container to run in the first place. It needs Spring as a library on the classpath (because we prefer to not reinvent the wheel), but is container agnostic in general.

为了简化与 DI 容器的集成,我们当然随后构建了与 Spring Java 配置、XML 命名空间以及 CDI 扩展,这样Spring Data就可以在简单的 CDI 场景.

To ease the integration with DI containers we've of course then built integration with Spring Java configuration, an XML namespace, but also a CDI extension, so that Spring Data can be used in plain CDI scenarios.

这篇关于Spring Data 存储库是如何实际实现的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆