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

2024-06-22

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

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

我对如何编码很感兴趣,并且查看了 Spring JPA 源代码和 API,但我找不到以下问题的答案:

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

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


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

  1. 如果存储库已使用自定义实现部分初始化(请参阅参考文档的那部分 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behaviour有关详细信息),并且调用的方法在该类中实现,调用将路由到该类。
  2. 如果该方法是查询方法(请参阅DefaultRepositoryInformation https://github.com/spring-projects/spring-data-commons/blob/1.12.2.RELEASE/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java#L163(了解如何确定),存储特定查询执行机制启动并执行确定在启动时为该方法执行的查询。为此,建立了一种解析机制,尝试识别在不同位置显式声明的查询(使用@Query在方法上,JPA 命名查询)最终回退到从方法名称派生查询。查询机制检测参见JpaQueryLookupStrategy https://github.com/spring-projects/spring-data-jpa/blob/1.10.2.RELEASE/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java#L181。查询派生的解析逻辑可以在PartTree https://github.com/spring-projects/spring-data-commons/blob/1.12.2.RELEASE/src/main/java/org/springframework/data/repository/query/parser/PartTree.java。可以看到商店特定的翻译为实际查询:在JpaQueryCreator https://github.com/spring-projects/spring-data-jpa/blob/1.10.2.RELEASE/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java#L214.
  3. 如果以上都不适用,则执行的方法必须是由特定于商店的存储库基类实现的方法(SimpleJpaRepository https://github.com/spring-projects/spring-data-jpa/blob/1.10.2.RELEASE/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java#L74如果是 JPA),并且调用将被路由到该实例的实例中。

实现该路由逻辑的方法拦截器是QueryExecutorMethodInterceptor,可以找到高级路由逻辑here https://github.com/spring-projects/spring-data-commons/blob/1.12.2.RELEASE/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java#L470.

这些代理的创建被封装到基于标准 Java 的工厂模式实现中。高级代理创建可以在RepositoryFactorySupport https://github.com/spring-projects/spring-data-commons/blob/1.12.2.RELEASE/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java#L191。然后,特定于商店的实现添加必要的基础设施组件,以便对于 JPA,您可以继续编写如下代码:

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

我明确提到这一点的原因是,应该清楚的是,从本质上讲,该代码的任何内容都不需要 Spring 容器来运行。它需要 Spring 作为类路径上的库(因为我们不喜欢重新发明轮子),但通常与容器无关。

为了简化与 DI 容器的集成,我们当然还构建了与 Spring Java 配置、XML 命名空间以及CDI 扩展 https://github.com/spring-projects/spring-data-jpa/tree/1.10.2.RELEASE/src/main/java/org/springframework/data/jpa/repository/cdi,这样Spring Data就可以用在普通的CDI场景中了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Data 存储库实际上是如何实现的? 的相关文章

随机推荐

  • Psycopg2:“模块”对象没有属性“连接”[重复]

    这个问题在这里已经有答案了 我正在尝试使用 psycopg2 连接到 postgres 数据库 import psycopg2 try conn psycopg2 connect dbname puppetdb user puppetdb
  • Python——发现它!牌

    我正在尝试模拟 Spot it 的牌组 使用 Python 制作卡片 对于那些不知道什么是 Spot it 的人这是一种流行的纸牌游戏 一副牌中有 55 张牌 每张牌上有 8 个随机符号 例如球 波浪等 每张牌都有 1 个与其他牌相同的符号
  • C#:如何获取字符串的第一个字符?

    第一个可以吗char通过执行以下操作可以检索字符串的 MyString ToCharArray 0 Just MyString 0 这使用了字符串 字符 http msdn microsoft com en us library syste
  • Java 中的泛型枚举

    我有一个基本的 Configuration 类 它在枚举中提供所有可能的键和相应值类型的类型 如下所示 public class Configuration public static enum Key FIRST KEY actual k
  • 如何在 Safari 中打开外部链接而不是应用程序的 UIWebView?

    我有一个Phonegap cordova 应用程序 我想在phonegap WebView中加载一些外部网页 并且我还有其他外部网页 我想在用户激活它们时在Safari中加载它们 通常 大多数人都会遇到想要在 WebView 中打开外部链接
  • Chrome DevTools 网络瀑布 - 请求之间的差距?

    我一直在对运行缓慢的 Web 应用程序进行一些重构 并设法减少请求数量和下载大小 以帮助改善这种情况 现在加载时间持续缩短 然而 在最后两个请求之前几乎没有经过任何时间 现在始终存在差距 问题 1 Chrome 网络视图中的这些 间隙 表示
  • 如何在主屏幕等视图之间切换

    如何在多个之间切换UIView正在使用一个UIViewController就像 iPhone 主屏幕一样 如果您需要澄清 请询问 请不要拒绝 使用 UIScrollView this http developer apple com iph
  • 使用 JavaScript 更改元素的 `innerHTML`

    好的 我是 JavaScript 新手 但我正在尝试更改innerHTML of a div元素 这是我的脚本不起作用 div change div 它应该可以工作 但由于某种原因没有 有什么帮助吗 而不是分配var1 to window
  • 如何通过 Get-AzureRmAppServicePlan 检索workerSize

    通过 Azure PowerShell cmdlet 创建新的 AppServicePlan 时New AzureRmAppServicePlan 预计我会添加一个WorkerSize例如小号 中号或大号 例如 appServicePlan
  • 使用前置摄像头拍摄图像,无需在android中打开相机应用程序[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我想使用 Android 手机的前置
  • 如何捕获退出 Winforms 应用程序的事件?

    如果用户想通过单击退出图标或按 ALT F4 退出应用程序 我想创建一个对话框 询问用户是否确实确定要退出 如何在应用程序实际关闭之前捕获此事件 查看关闭时 http msdn microsoft com en us library sys
  • ANDROID 上的磁场传感器校准

    我正在制作一个用作指南针的应用程序 我使用加速度计和磁场传感器来计算方位角 sensor getOrientation 我正在寻找可以提高磁场传感器精度的东西 因为我得到的精度状态是不可靠的 有人知道这件事吗 我正在寻找一些可以硬编码的东西
  • Java错误:表达式的非法开始

    我基本上正在完善 完成并尝试从 Java 初学者的参考书中编译测试代码 目标是创建一个猜谜游戏 其中目标位于 3 个连续的单元格中 我将位置保存在一个数组中 并且用户猜测单元格号 逐个细胞地摧毁目标细胞 我在这里查看了六篇关于同一错误的帖子
  • 如何获取 std::wstring 的字节大小?

    我在用std wstring作为我的 Unicode 样式字符串 现在我想得到 a 的字节大小wstring 如果我使用size 的方法wstring 我只得到字符总数 在我的wstring 但字节应该是 size 2 有没有官方的方法来获
  • 我可以阻止修改 Python 中的对象吗?

    我想控制全局变量 或全局范围的变量 使其在程序初始化代码中仅设置一次 然后锁定它们 我使用 UPPER CASE VARIABLES 作为全局变量 但我想有一个确定的方法来不更改变量 python 是否提供该 或类似 功能 如何控制全局范围
  • PHP:在 AJAX/JSON 中提交表单时出现问题?

    目前我有以下代码 home php
  • 使用亚马逊步骤函数,如何编写引用当前时间的选择运算符?

    在 aws step 函数中文档 http docs aws amazon com step functions latest dg amazon states language choice state html amazon state
  • 2012 年推荐的 jQuery 模板? [复制]

    这个问题在这里已经有答案了 jQuery 模板已被弃用一段时间了 我有一些 JavaScript 对象形式的数据 我想将其格式化为 HTML 并附加到 DOM 如今最好的方法是什么 我应该构建一个 HTML 字符串吗 我应该通过 jQuer
  • 我可以使用 EnableStatic 来配置 IPv6 地址(使用 WMI)吗?

    我想使用 WMI C 语言 来配置静态 IPv6 地址 配置静态 IPv4 地址可以正常使用EnableStatic 它是名为的 WMI 类的一部分Win32 NetworkAdapterConfiguration 谁能帮我使用 WMI 配
  • Spring Data 存储库实际上是如何实现的?

    我在项目中使用 Spring Data JPA 存储库已经有一段时间了 我知道以下几点 在存储库接口中 我们可以添加类似的方法findByCustomerNameAndPhone 假设customerName and phone是域对象中的