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

查看:167
本文介绍了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()这样的方法(假设 customerName phone 是域对象中的字段。)

  • 然后,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. 如何在运行时生成存储库实现类&正在实施和注入的方法?

  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. 如果已使用自定义实现部分初始化存储库(请参阅< a href =https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behaviour =noreferrer>参考文档的那部分有关详细信息),并且调用的方法在该类中实现,调用在那里进行路由。

  2. 如果方法是查询方法(请参阅 DefaultRepositoryInformation 如何确定),商店spe cific查询执行机制启动并执行确定在启动时为该方法执行的查询。为此,尝试在各个地方识别显式声明的查询(在方法上使用 @Query ,JPA命名查询)最终回退到查询派生方法名称。有关查询机制检测,请参阅 JpaQueryLookupStrategy 。可以在 PartTree 。可以看到商店特定的翻译成实际查询,例如,在 JpaQueryCreator

  3. 如果以上都不适用该方法执行必须是由特定于商店的存储库基类实现的( SimpleJpaRepository ,如果是JPA)和该调用被路由到该实例中。

  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的Factory模式实现中。高级代理创建可以在 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天全站免登陆