当前位置: 首页 > 面试题库 >

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

欧阳元魁
2023-03-14
问题内容

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

  • 在存储库接口中,我们可以添加类似的方法findByCustomerNameAndPhone()(假设customerNamephone是域对象中的字段)。
  • 然后,Spring通过在运行时(在应用程序运行期间)实现上述存储库接口方法来提供实现。
    我对它的编码方式很感兴趣,并查看了Spring JPA源代码和API,但是找不到以下问题的答案:

  • 如何在运行时生成存储库实现类以及如何实现和注入方法?

  • Spring Data JPA是否使用CGlib或任何字节码操作库来实现方法并动态注入?
    你能否为上述查询提供帮助,并提供任何受支持的文档?

问题答案:

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

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

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



 类似资料:
  • 我对SpringData和JPA有问题。当我向HomeRepository接口添加方法时,我得到一个错误。我使用的是JPararePository接口,在pom.xml文件中有一个MySQL数据库集。这些只是我对spring的开始,所以我需要一些了解spring的人的帮助。下面是我的代码和日志: 主页库: 用户存储库: 日志:

  • 我们已经为Dev、QA、Prod实例启用了spring分析,这些实例正在AWS EC2上运行。 我们有不同的属性文件,如: application-dev.properties application-qa.properties application-prod.properties 并且我们已经在这些文件中配置了数据源,如 spring.datasource.username=test spri

  • 我正在做一个项目,我们有很多实体,我们将在这些实体上进行CRUD操作。我创建了一个基本实体类,在所有其他实体中,我扩展了基本实体类,该类具有诸如created\u date、created\u by、last\u updated\u date、last\u updated\u by等公共字段。现在,我想在Spring CrudRepository方法上实现aspect,并在保存时设置上述字段。 我

  • 我查阅了许多存储库设计模式教程,如 https://asperbrothers.com/blog/implement-repository-pattern-in-laravel/ https://www.larashout.com/how-to-use-repository-pattern-in-laravel https://laravelarticle.com/repository-desig

  • (我不计算单词可寻址的机器,也不计算Alpha(字节可寻址但缺少字节加载/存储指令)。我指的是ISA本身支持的最窄的存储指令。) 在我的研究中,当回答现代x86硬件不能将一个字节存储到内存中吗?时,我发现Alpha AXP省略字节存储的原因是假设它们将被实现为真正的字节存储到缓存中,而不是包含字的RMW更新。(因此,它会使L1d缓存的ECC保护更加昂贵,因为它需要字节粒度而不是32位)。 我假设提

  • 我有一个artifactoryoss(最新版本)的实例在本地docker容器中运行 我们还有一个Artifactory(非OSS)的远程实例正在运行 在我的本地实例中,我设置了一个包类型为Ivy的远程存储库,指向我们在远程非OSS实例中设置的每个存储库 创建远程存储库配置后,我可以查看我创建的每个远程存储库及其在应用程序下提供的工件--