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

时间:2016-07-21 16:42:10

标签: java spring spring-data repository-pattern ddd-repositories

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

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

我感兴趣的是如何对它进行编码,并且我已经查看了Spring JPA源代码& API,但我无法找到以下问题的答案:

  1. 如何在运行时生成存储库实现类&正在实施和注入的方法?
  2. Spring Data JPA是否使用CGlib或任何字节码操作库来实现方法并动态注入?
  3. 您能帮助解决上述问题并提供任何支持的文档吗?

1 个答案:

答案 0 :(得分:104)

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

  1. 如果已使用自定义实现部分初始化存储库(有关详细信息,请参阅that part of the reference documentation),并且在该类中实现调用的方法,则会在此处路由调用。
  2. 如果该方法是查询方法(请参阅DefaultRepositoryInformation了解如何确定),则特定于商店的查询执行机制将启动并执行确定在启动时为该方法执行的查询。为此,尝试在各个位置识别显式声明的查询(在方法上使用@Query,JPA命名查询)最终回退到方法名称的查询派生。有关查询机制检测,请参阅JpaQueryLookupStrategy。可以在PartTree中找到查询派生的解析逻辑。可以看到商店特定的翻译成实际查询,例如,在JpaQueryCreator
  3. 如果以上都不适用,则执行的方法必须是由特定于商店的存储库基类(在JPA的情况下为SimpleJpaRepository)实现的方法,并且将调用路由到该实例中。
  4. 实现路由逻辑为QueryExecutorMethodInterceptor的方法拦截器,可以找到高级路由逻辑here

    这些代理的创建被封装到基于标准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 extension的集成,以便可以在普通的CDI场景中使用Spring Data。