Spring Data 存储库实际上是如何实现的?

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

  • 在存储库接口中,我们可以添加类似于 findByCustomerNameAndPhone()的方法(假设 customerNamephone是域对象中的字段)。
  • 然后,Spring 通过在运行时(在应用程序运行期间)实现上述存储库接口方法来提供实现。

我感兴趣的是这是如何被编码的,我看了 Spring JPA 源代码和 API,但是我找不到以下问题的答案:

  1. 如何在运行时生成存储库实现类以及如何实现和注入方法?
  2. Spring Data JPA 是否使用 CGlib 或任何字节码操作库来实现方法和动态注入?

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

41636 次浏览

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

  1. 如果存储库已经用自定义实现部分初始化(详见 那部分参考文档) ,并且调用的方法是在该类中实现的,则调用将路由到那里。
  2. 如果该方法是一个查询方法(如何确定,请参阅 DefaultRepositoryInformation) ,则存储特定的查询执行机制启动并执行在启动时为该方法确定的查询。为此,一种解析机制已经到位,它试图在不同的地方(使用方法上的 @Query,JPA 命名的查询)识别显式声明的查询,最终回到从方法名称派生的查询。有关查询机制检测,请参见 JpaQueryLookupStrategy。查询派生的解析逻辑可以在 PartTree中找到。可以看到存储特定的转换为实际查询,例如在 JpaQueryCreator中。
  3. 如果上述方法都不能应用,那么执行的方法必须是由特定于存储库的存储库基类(如果是 JPA,则为 SimpleJpaRepository)实现的方法,并且调用将被路由到该存储库基类的实例中。

实现该路由逻辑的方法拦截器为 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 场景中使用。