前几天把整合SpringDataJPA和Spring讲了一下 , 现在空出了点时间 , 也对SPringDataJPA的运行有点好奇 , 毕竟 , 只要编写一个接口并继承两个JPAReposity相关的接口就能自动完成单表基础操作. 于是写了个单表的CRUD来DEBUG看看SpringDataJPA的实际运行原理 .
运行环境
- JDK 1.8
- IDEA 19.01
- Maven 3.6
- Mysql 5.17
运行测试
项目直接套用之前使用整合的那个 , 编写一个测试类进行单测
1 |
|
给查询所有方法调用打上断点然后debug运行:
运行到这里 , 程序正常停住 , 我们按F8往下执行一步 , 可以发现 我们 进入了一个叫做JDKDynamicAOPProxy
的类中的invoke()
方法 , 从这里可以看出 , JPA在运行时其实是创建了一个动态代理对象来执行方法 , 这里也就能解释为什么 , 只要继承JPA接口即可完成CRUD功能.
再往下一步一步执行 , 我们可以发现下面的变量监控中出现了一个代理对象proxy
, 类型是SimpleJPAReposity
, 并且执行的方法也是我们调用的Findall
方法.
但是我们并不确定 , 实际执行的对象就是这个类型的 .
继续往下运行 , 可以看到有个target对象(代理执行的真正对象在这里了) , 这里可以看到初始化为null , 我们继续往下执行 , 可以看到在这里 , 有了对target的实际赋值操作 :
这个时候我们返回去再看看target初始化的地方:
可以看到target有了真实的引用地址了 , 这个指向的地址类型可以发现 , 其实也就是最开始我们推断的SimpleJPAReposity
.
点进去看看 , 可以发现这个类实现了之前我们编写的持久层继承的两个JPA的接口:
于是在这里我便往下翻 , 很快就找到了我们要调用的FindAll
方法:
可以看到 , 这里的返回它调用了当前类中的getQuery
方法 , 我们点过去看一下:
在这个getQuery
方法里 , 返回的是this.em.createQuery()
方法 , 有没有对这个createQuery()
方法有点熟悉? 这个方法就是java 的 JPA规范实现的创建创建查询的方法 , 那么这个em
的类型我们其实已经可以知道了 , 我们点过去看一下:
和我想象的一样 , 其实就是一个EntityManager
类型的对象.
到这里 , SpringDataJPA的方法实现原理已经基本上清楚了
总结
其实SPringDataJPA就是对java的JPA规范API进行了一个二次封装 , 更加贴近于面向对象的操作 , 简化了我们对JPA的配置.
其内部还是EntityManager
管理器在对持久化单元进行的操作.