添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Spring Data JPA 源码分析

前言

欢迎大家关注我的微信公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。

一、概述

Spring Data JPA 源码很少有人去分析,原因如下:

1、Spring Data JPA 地位没有之前学习的框架高,大家习惯把它当成一个工具来用了,不愿意对它进行源码层次的解读。

2、开发 Dao 接口( ResumeDao ),接口的实现对象肯定是通过动态代理来完成的(增强),代理对象的产生过程追源码很难追,特别特别讲究技巧。

这里,我来和大家一起分析下源码, Spring Data JPA 源码剖析的主要的过程,就是代理对象产生的过程。

我们发现 resumeDao 是一个代理对象,这个代理对象的类型是 SimpleJapRepository 。代理对象在 h 里产生。



二、这个代理对象是怎么产生,过程是怎样

以往:如果要给一个对象产生代理对象,我们知道是在 AbstractApplicationContext refresh 方法中, 那么能不能在这个方法中找到什么我们当前场景的线索?





进入该方法以后,断点到这一行,输入 beanName.equals("resumeDao")





新的疑问又来了?

问题1 : 为什么会给它指定为一个 JpaRespositoryFactoryBean # getObject 方法返回具体的对象?

问题2 :指定这个 FactoryBean 是在什么时候发生的?

首先解决问题2:



传入一个 resumeDao 就返回了一个已经指定 class JpaRepositoryFactoryBean BeanDefinition 对象了,那么应该在上图中的 get 时候就有了,所以断点进入:

private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap(256);



问题来了,什么时候 put map 中去的?我们定位到了一个方法在做这件事:

mergedBeanDefinitions.put Find Usages 反调找到该方法:





我们发现,传入该方法的时候, BeanDefintion 中的 class 就已经被指定为 FactoryBean 了,那么观察该方法的调用栈。











继续跟进,发现 BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(configuration.getRepositoryFactoryBeanClassName()); 这行代码已经产生了 JpaRepositoryFactoryBean






通过上述追踪我们发现, <jpa:repository basePackage ,扫描到的接口,在进行 BeanDefintion 注册时候, class 会被固定的指定为 JpaRepositoryFacotryBean

至此,问题2 追踪完毕。

那么接下来,我们再来追踪问题1 JpaRespositoryFactoryBean 是一个什么样的类,它是一个 FactoryBean ,我们重点关注 FactoryBean getObject 方法。


















由此可⻅, JdkDynamicAopProxy 会生成一个代理对象类型为 SimpleJpaRespository ,而该对象的增强逻辑就在 JdkDynamicAopProxy 类的 invoke 方法中。

至此,问题1追踪完毕。

三、这个代理对象类型SimpleJpaRepository有什么特别的?





原来 SimpleJpaRepository 类实现了 JpaRepository 接口和 JpaSpecificationExecutor 接口。



Spring Data JPA 级别的封装也就到这了,剩下的是 JPA hibernate 的源码了,这也印证了我们刚开始讲的 Spring Data JPA 是对 JPA 的高级封装。

编辑于 2021-05-14 22:45

文章被以下专栏收录