Spring Data JPA详解
Spring Data Jpa 是应用于Dao层的⼀个框架,简化数据库开发的,作用和Mybatis框架⼀样,但是在使用方式和底层机制是有所不同的,最明显的⼀个特点,Spring Data Jpa 开发Dao的时候,很多场景我们 连sql语句都不需要开发,且由Spring出品
Spring Data JPA 概述:
什么是 Spring Data JPA:
Spring Data JPA 是 Spring 基于JPA 规范的基础上封装的⼀套 JPA 应用框架,可使开发者用极简的代码即可实现对数据库的访问和操作,它提供了包括增删改查等在内的常用功能,学习并使用 Spring Data JPA 可以极大提高开发效率
说明:Spring Data JPA 极大简化了数据访问层代码
如何简化呢,使用了Spring Data JPA,我们Dao层中只需要写接口,不需要写实现类,就自动具有 了增删改查,分页查询等方法
使用Spring Data JPA 很多场景下不需要我们自己写sql语句
什么是JPA 规范:Java Persistence API(JPA) 是一套用于管理和持久化 Java 对象与关系数据库之间数据的标准规范,JPA 主要用来将 Java 对象与数据库中的表记录相互映射,通过对象化的方式进行数据库操作,简化了数据库的访问
注意了,对应的与ORM的区别是:ORM 是一种技术,它通过将数据库表映射到对象来实现对象和关系数据之间的转换,ORM 的目标是使开发者能够以面向对象的方式与数据库交互,而不必编写大量的 SQL 语句,典型是mybatis,通常使用一些xml来对应类,而JPA规范通常是使用一些注解来进行操作,所以如果mybatis本身也可以完全使用注解来完成,那么也可以称mybatis是一种JPA规范操作的框架(虽然现实并不是)
简单来说:
JPA是一种标准规范,定义了如何通过注解和实体类进行对象关系映射(ORM),JPA 注重自动化,通过注解和标准 API(如 EntityManager)来管理实体的生命周期、关系和持久化操作
ORM侧重于映射,如MyBatis 提供了一种将 SQL 查询直接映射到 Java 方法的方式,并且允许开发者手动编写 SQL 查询,这使得它非常灵活,但与 JPA 的自动化和规范化有很大的不同,但是呢,JPA最终也是操作映射的,所以可以称JPA也是一种ORM的规范 ,即JPA是一个实现了ORM概念的Java规范(前提是有使用了这个规范的框架,否则只是规范)
Spring Data 家族:
Spring Data JPA,JPA规范和Hibernate之间的 关系
Spring Data JPA 是 Spring 提供的⼀个封装了JPA 操作的框架,而JPA 仅仅是规范,单独使用规范无法 具体做什么,那么Spring Data JPA 、 JPA规范 以及 Hibernate (是JPA 规范的⼀种实现,了解这个即可)之间的关系是什么:
即:JPA 是⼀套规范,内部是由接口和抽象类组成的,Hiberanate 是⼀套成熟的 ORM 框架,而且 Hiberanate 实现了 JPA 规范,所以可以称 Hiberanate 为 JPA 的⼀种实现方式,我们使用 JPA 的 API 编程,意味着站在更高的角度去看待问题(面向接口编程), Spring Data JPA 是 Spring 提供的⼀套对 JPA 操作更加⾼级的封装,是在 JPA 规范下的专门用来进行数 据持久化的解决方案
也就是说,Spring Data JPA封装后,需要使用该jpa规范的框架,可以直接使用封装好的(也就是Spring Data JPA),而不用自行实现了(或者不用使用自身的,因为Spring Data JPA在原来的jpa基础上有所增强)
也要注意:虽然JPA定义了接口和规范,但它并没有提供实际的实现代码,因此,需要一个具体的实现来执行这些操作,Hibernate是JPA规范的一个常见实现,提供了实际的持久化逻辑,所以当Hibernate操作时,通常建议与该jpa整合,使得Hibernate也使用这个增强的规范,使得我们在这个规范下编写代码,从而不用自身的不增强的jpa了
说了这么多,其实就一句话:有jpa规范的框架,自身jpa还不够,我需要增强的jpa(Spring Data JPA)
Spring Data JPA 应用:
需求:使用 Spring Data JPA 完成对 tb_resume 表(简历表)的Dao 层操作(增删改查,排序, 分页等)
创建数据库:
CREATE DATABASE wd CHARACTER SET utf8;
USE wd;
CREATE TABLE tb_resume(
id BIGINT ( 20 ) NOT NULL AUTO_INCREMENT ,
address VARCHAR ( 255 ) DEFAULT NULL ,
NAME VARCHAR ( 255 ) DEFAULT NULL ,
phone VARCHAR ( 255 ) DEFAULT NULL ,
PRIMARY KEY ( ` id` )
) ;
INSERT INTO tb_resume VALUES ( 1 , '北京' , '张三' , '131000000' ) ;
INSERT INTO tb_resume VALUES ( 2 , '上海' , '李四' , '151000000' ) ;
INSERT INTO tb_resume VALUES ( 3 , '广州' , '王五' , '153000000' ) ;
开发步骤:
我们这里操作的是整合Hibernate的,而不是单纯的Hibernate,所以呢,如果需要学习单纯的Hibernate,那么可以百度(使用整合的其实就够啦,这个整合其实不只是jpa规范继续增强,也与Spring整合了,类似mybatis整合spring,只不过这里多了一个jpa规范而已,或者说多几个注解)
首先创建项目,然后我们引入依赖:
<?xml version="1.0" encoding="UTF-8"?>
< project xmlns = " http://maven.apache.org/POM/4.0.0"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
< modelVersion> 4.0.0</ modelVersion>
< groupId> org.example</ groupId>
< artifactId> jpa</ artifactId>
< version> 1.0-SNAPSHOT</ version>
< properties>
< maven.compiler.source> 11</ maven.compiler.source>
< maven.compiler.target> 11</ maven.compiler.target>
</ properties>
< dependencies>
< dependency>
< groupId> junit</ groupId>
< artifactId> junit</ artifactId>
< version> 4.12</ version>
< scope> test</ scope>
</ dependency>
< dependency>
< groupId> org.springframework.data</ groupId>
< artifactId> spring-data-jpa</ artifactId>
< version> 2.1.8.RELEASE</ version>
</ dependency>
< dependency>
< groupId> org.glassfish.web</ groupId>
< artifactId> javax.el</ artifactId>
< version> 2.2.6</ version>
</ dependency>
< dependency>
< groupId> org.aspectj</ groupId>
< artifactId> aspectjweaver</ artifactId>
< version> 1.8.13</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-context</ artifactId>
< version> 5.1.12.RELEASE</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-orm</ artifactId>
< version> 5.1.12.RELEASE</ version>
</ dependency>
< dependency>
< groupId> org.hibernate</ groupId>
< artifactId> hibernate-entitymanager</ artifactId>
< version> 5.4.0.Final</ version>
</ dependency>
< dependency>
< groupId> org.hibernate</ groupId>
< artifactId> hibernate-validator</ artifactId>
< version> 5.4.0.Final</ version>
</ dependency>
< dependency>
< groupId> mysql</ groupId>
< artifactId> mysql-connector-java</ artifactId>
< version> 5.1.46</ version>
</ dependency>
< dependency>
< groupId> com.alibaba</ groupId>
< artifactId> druid</ artifactId>
< version> 1.1.21</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-test</ artifactId>
< version> 5.1.12.RELEASE</ version>
</ dependency>
</ dependencies>
</ project>
创建jdbc.properties文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/wd?characterEncoding=utf8&useSSL=false
jdbc.username=root
jdbc.password=123456
创建com.pojo包,然后创建Resume类:
package com. pojo ;
import javax. persistence. * ;
@Entity
@Table ( name = "tb_resume" )
public class Resume {
@Id
@GeneratedValue ( strategy = GenerationType . IDENTITY )
@Column ( name = "id" )
private Long id;
@Column ( name = "name" )
private String name;
@Column ( name = "address" )
private String address;
@Column ( name = "phone" )
private String phone;
public Long getId ( ) {
return id;
}
public void setId ( Long id) {
this . id = id;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public String getAddress ( ) {
return address;
}
public void setAddress ( String address) {
this . address = address;
}
public String getPhone ( ) {
return phone;
}
public void setPhone ( String phone) {
this . phone = phone;
}
@Override
public String toString ( ) {
return "Resume{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
", phone='" + phone + '\'' +
'}' ;
}
}
创建com.dao包,然后创建ResumeDao接口:
package com. dao ;
import com. pojo. Resume ;
import org. springframework. data. jpa. repository. JpaRepository ;
import org. springframework. data. jpa. repository. JpaSpecificationExecutor ;
public interface ResumeDao extends JpaRepository < Resume , Long > ,
JpaSpecificationExecutor < Resume > {
}
配置 Spring 的配置文件,spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
< beans xmlns = " http://www.springframework.org/schema/beans"
xmlns: context= " http://www.springframework.org/schema/context"
xmlns: jpa= " http://www.springframework.org/schema/data/jpa"
xmlns: tx= " http://www.springframework.org/schema/tx"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= "
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
https://www.springframework.org/schema/data/jpa/spring-jpa.xsd" >
< context: component-scan base-package = " com" />
< context: property-placeholder location = " classpath:jdbc.properties" />
< bean id = " dataSource" class = " com.alibaba.druid.pool.DruidDataSource" >
< property name = " driverClassName" value = " ${jdbc.driver}" />
< property name = " url" value = " ${jdbc.url}" />
< property name = " username" value = " ${jdbc.username}" />
< property name = " password" value = " ${jdbc.password}" />
</ bean>
< bean id = " entityManagerFactory" class = " org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
< property name = " dataSource" ref = " dataSource" />
< property name = " packagesToScan" value = " com.pojo" />
< property name = " persistenceProvider" >
< bean class = " org.hibernate.jpa.HibernatePersistenceProvider" > </ bean>
</ property>
< property name = " jpaDialect" >
< bean class = " org.springframework.orm.jpa.vendor.HibernateJpaDialect" > </ bean>
</ property>
< property name = " jpaVendorAdapter" >
< bean class = " org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
< property name = " generateDdl" value = " false" />
< property name = " database" value = " MYSQL" />
< property name = " databasePlatform" value = " org.hibernate.dialect.MySQLDialect" />
< property name = " showSql" value = " true" />
</ bean>
</ property>
</ bean>
< jpa: repositories base-package = " com.dao" entity-manager-factory-ref = " entityManagerFactory"
transaction-manager-ref = " transactionManager" />
< bean id = " transactionManager" class = " org.springframework.orm.jpa.JpaTransactionManager" >
< property name = " entityManagerFactory" ref = " entityManagerFactory" />
</ bean>
< tx: annotation-driven/>
</ beans>
至此,对应的spring扫描,以及数据源配置,以及jpa工厂配置(整合了hibernate)
我们在测试资源文件夹下创建com.test包,然后创建Test1类:
package com. test ;
import com. dao. ResumeDao ;
import com. pojo. Resume ;
import org. junit. Test ;
import org. junit. runner. RunWith ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. test. context. ContextConfiguration ;
import org. springframework. test. context. junit4. SpringJUnit4ClassRunner ;
import java. util. Optional ;
@RunWith ( SpringJUnit4ClassRunner . class )
@ContextConfiguration ( locations = { "classpath:spring.xml" } )
public class Test1 {
@Autowired
private ResumeDao resumeDao;
@Test
public void testFindById ( ) {
Optional < Resume > optional = resumeDao. findById ( 1l ) ;
Resume resume = optional. get ( ) ;
System . out. println ( resume) ;
}
}
直接进行访问,若出现了数据,代表操作成功,至此我们搭建好了环境的处理
我们继续学习:
继续在该测试类中补充如下:
@Test
public void testFindOne ( ) {
Resume resume = new Resume ( ) ;
resume. setId ( 1l ) ;
Example < Resume > of = Example . of ( resume) ;
Optional < Resume > one = resumeDao. findOne ( of) ;
System . out. println ( one. get ( ) ) ;
}
执行看看结果,然后我们继续补充:
@Test
public void testSave ( ) {
Resume resume = new Resume ( ) ;
resume. setId ( 1l ) ;
resume. setName ( "让人人" ) ;
Resume save = resumeDao. save ( resume) ;
resume. setName ( "他人" ) ;
System . out. println ( save) ;
resume. setId ( null ) ;
Resume save1 = resumeDao. save ( resume) ;
resume. setName ( "和" ) ;
System . out. println ( save1) ;
}
只所以会造成更新和新增的实例不同,根本原因还是方法的原因,可能在以后的版本中会有所改变,这里了解即可
上面的操作方式有点像mybatis-plus(mp),只是细节不同而已,当然了,mp通常不能自动的解决复杂sql(需要写sql,即半自动,虽然mp还有对应的依赖进行增强实现全自动,但那是其他依赖,不是mp自身存在的,了解即可),而jpa通常是可以的(即全自动,这里我们看后面)
如果考虑mp的增强实现全自动,那么对应的依赖加上mp(一般可以找到:mybatis-plus-join依赖)和jpa只是一种设计理念和操作方式不同的框架而已,具体使用谁,看自身情况
我们继续:
@Test
public void testDelete ( ) {
resumeDao. deleteById ( 2l ) ;
}
我们继续:
@Test
public void testFindAll ( ) {
List < Resume > all = resumeDao. findAll ( ) ;
for ( Resume resume : all) {
System . out. println ( resume) ;
}
}
@Test
public void testSort ( ) {
Sort sort = new Sort ( Sort. Direction . DESC , "id" ) ;
List < Resume > list = resumeDao. findAll ( sort) ;
for ( int i = 0 ; i < list. size ( ) ; i++ ) {
Resume resume = list. get ( i) ;
System . out. println ( resume) ;
}
}
上面基本都是使用继承的接口的方法,我们也可以自定义一个:
回到前面的接口ResumeDao,在里面加上如下:
@Query ( "from Resume where id =?1" )
public List < Resume > findByJpql ( Long id) ;
我们回到测试类,然后加上如下:
@Test
public void testJpql ( ) {
List < Resume > byJpql = resumeDao. findByJpql ( 6l ) ;
for ( Resume s : byJpql) {
System . out. println ( s) ;
}
}
我们还可以继续补充参数:
@Query ( "from Resume where id =?1 and name = ?2" )
public List < Resume > findByJpql ( Long id, String name) ;
修改一下:
@Test
public void testJpql ( ) {
List < Resume > byJpql = resumeDao. findByJpql ( 6l , "让人" ) ;
for ( Resume s : byJpql) {
System . out. println ( s) ;
}
}
进行测试吧,我们还可以操作原生的sql,我们在ResumeDao接口里面继续添加:
@Query ( value = "select * from tb_resume where id =?1 and name = ?2" , nativeQuery = true )
public List < Resume > findBySql ( Long id, String name) ;
继续测试:
@Test
public void testSql ( ) {
List < Resume > sql = resumeDao. findBySql ( 6l , "让人" ) ;
for ( Resume s : sql) {
System . out. println ( s) ;
}
}
注意:占位的基本都是解决了对应的sql注入,所以知道即可,还有我们这里还是建议使用原生的,这样不用框架来处理了,当然了,直接的使用原生的,可能只是对使用的那个数据库进行支持,并且不够动态(考虑修改类属性时,原生的没有提示),但是对操作更加复杂的sql有方便的处理
我们还可以这样:
在对应的ResumeDao接口中加上如下:
public List < Resume > findByNameLike ( String name) ;
public List < Resume > findByName ( String name) ;
我们进行测试:
@Test
public void testMethodName ( ) {
List < Resume > resumes = resumeDao. findByNameLike ( "他%" ) ;
for ( Resume resume : resumes) {
System . out. println ( resume) ;
}
List < Resume > resumes1 = resumeDao. findByName ( "他" ) ;
for ( Resume resume : resumes1) {
System . out. println ( resume) ;
}
}
当然了,如果存在注解,那么操作注解的,如果存在继承的,那么操作继承的
现在我们已经说明了四种:
还有一种:动态查询,其中这里也是继承的(接口可以多继承,也可以说是第一种操作),我们看接口:
public interface ResumeDao extends JpaRepository < Resume , Long > ,
JpaSpecificationExecutor < Resume > {
}
public interface JpaSpecificationExecutor < T > {
Optional < T > findOne ( @Nullable Specification < T > var1) ;
List < T > findAll ( @Nullable Specification < T > var1) ;
Page < T > findAll ( @Nullable Specification < T > var1, Pageable var2) ;
List < T > findAll ( @Nullable Specification < T > var1, Sort var2) ;
long count ( @Nullable Specification < T > var1) ;
}
我们点开上面的Specification:
public interface Specification < T > extends Serializable {
long serialVersionUID = 1L ;
static < T > Specification < T > not ( Specification < T > spec) {
return Specifications . negated ( spec) ;
}
static < T > Specification < T > where ( Specification < T > spec) {
return Specifications . where ( spec) ;
}
default Specification < T > and ( Specification < T > other) {
return Specifications . composed ( this , other, CompositionType . AND ) ;
}
default Specification < T > or ( Specification < T > other) {
return Specifications . composed ( this , other, CompositionType . OR ) ;
}
@Nullable
Predicate toPredicate ( Root < T > var1, CriteriaQuery < ? > var2, CriteriaBuilder var3) ;
}
那么我们直接在测试类中加上如下:
@Test
public void testSpecification ( ) {
Specification < Resume > objectSpecification = new Specification ( ) {
@Override
public Predicate toPredicate ( Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path name = root. get ( "name" ) ;
Predicate predicate = criteriaBuilder. equal ( name, "他" ) ;
return predicate;
}
} ;
Optional < Resume > one = resumeDao. findOne ( objectSpecification) ;
Resume resume = one. get ( ) ;
System . out. println ( resume) ;
}
继续测试一下:
@Test
public void testSpecificationTest ( ) {
Specification < Resume > objectSpecification = new Specification ( ) {
@Override
public Predicate toPredicate ( Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path name = root. get ( "name" ) ;
Path address = root. get ( "address" ) ;
Predicate predicate = criteriaBuilder. equal ( name, "让人" ) ;
Predicate predicate1 = criteriaBuilder. like ( address. as ( String . class ) , "分%" ) ;
Predicate and = criteriaBuilder. and ( predicate, predicate1) ;
return and;
}
} ;
Optional < Resume > one = resumeDao. findOne ( objectSpecification) ;
Resume resume = one. get ( ) ;
System . out. println ( resume) ;
}
考虑一个问题,为什么要补充address.as(String.class),虽然说是变成字符串,会加上引号,但是在sql中,如果我们默认将所有数据都加上引号,不就行了,也就是无论是否是字符串都加上,为什么不这样处理,其实大多数框架或者其框架里面操作sql的部分通常都会考虑到是否添加,有些框架可能都加上单引号,有些可能为了严谨而不加上,而是看情况,大多数都是看情况的(如mybatis,通常考虑其底层逻辑的处理,如预处理对象:PreparedStatement,在41章博客有说明,mybatis内部一般是操作这个预处理对象的,然后操作数据库的),而这里通常也是,所以也可以不用设置as(String.class),具体可以自行测试
操作一下分页:
@Test
public void testPage ( ) {
Pageable pageable = PageRequest . of ( 1 , 2 ) ;
Page < Resume > all = resumeDao. findAll ( pageable) ;
System . out. println ( all) ;
List < Resume > collect = all. get ( ) . collect ( Collectors . toList ( ) ) ;
for ( Resume resume : collect) {
System . out. println ( resume) ;
}
System . out. println ( all. get ( ) . count ( ) ) ;
System . out. println ( all. getTotalElements ( ) ) ;
}
Spring Data JPA 执行过程源码分析:
Spring Data Jpa 源码很少有人去分析,因为Spring Data Jpa 地位没有之前学习的框架高,习惯把它当成⼀个工具来用,并且接口的实现对象肯定是通过动态代理来完成的(也就是增强),且代理对象的产生过程追源码很难追,所以少有人分析
一般这个代理对象是这样的:
也就是这个类:
@Repository
@Transactional (
readOnly = true
)
public class SimpleJpaRepository < T , ID> implements JpaRepositoryImplementation < T , ID> {
}
@NoRepositoryBean
public interface JpaRepositoryImplementation < T , ID> extends JpaRepository < T , ID> , JpaSpecificationExecutor < T > {
void setRepositoryMethodMetadata ( CrudMethodMetadata var1) ;
default void setEscapeCharacter ( EscapeCharacter escapeCharacter) {
}
}
public interface ResumeDao extends JpaRepository < Resume , Long > ,
JpaSpecificationExecutor < Resume > {
}
注意:上面不是代理对象的,是操作代理拦截后的返回的结果显示(当然,对应的调试显示也会因为是toString的结果,而这个toString的结果是代理接口的实现他的类的toString,如果有多个实现类,那么看你操作谁的方法了(创建代理中的指定的实现类的处理,如指定谁的实现接口,因为是匿名的,值已经得到了哦),就操作谁的toString),所以会出现对应的类,其接口的对象在上面的显示是:$Proxy39
所以说,对应的ResumeDao是代理对象,一般我们可以称这三个为代理对象,比如:
1:jdk代理生成的对象
2:jdk代理对象拦截后返回的对象(也就是上面的SimpleJpaRepository)
3:封装了jdk代理或者其他代理操作的对象
这三个都可以称为代理对象,只不过我们通常以第一个为主,所以如果在后面或者前面说明是代理对象时,应该就是这三个之中的
这里为了进行区分:我们称接口的对象是代理对象,其返回的对象是代理所产生的对象,那么ResumeDao就是代理对象
他使用什么代理呢,是JDK 动态代理
一般来说:在使用 JDK 动态代理时,每次调用 Proxy.newProxyInstance()方法都会创建一个新的代理对象,这些代理对象是由 JVM 在运行时动态生成的,并加载这些字节码来创建代理类的实例(也就是考虑jvm,或者java自身的处理字节码文件,并考虑使用类加载器的操作)
在 JDK 动态代理中,生成的代理类的名称是根据一定的规则生成的,通常遵循以下格式:
当然,也可能存在有些框架不返回代理的可能,也就是说,在内部得到代理对象后,本质上又创建了一个实例返回给接口(考虑接口的子类),该子类他内部处理对应的代理对象,所以他本身不是代理对象,只不过间接的处理了代理对象而已
那么我们先拿取之前的代码:
@Test
public void testFindById ( ) {
Optional < Resume > optional = resumeDao. findById ( 1l ) ;
Resume resume = optional. get ( ) ;
System . out. println ( resume) ;
}
在这里进行分析吧
开始分析:
首先我们需要找到产生的过程,一般由于他是Spring来赋值的,自然在Spring中进行处理,而Spring中存在AbstractApplicationContext的refresh方法中进行加载的,一般是这里(之前学习了Spring的底层原理,在那里可以找到):
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
}
finishBeanFactoryInitialization ( beanFactory) ;
给上面打上断点,然后进行启动:
进入上面的方法:
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
protected void finishBeanFactoryInitialization ( ConfigurableListableBeanFactory beanFactory) {
if ( beanFactory. containsBean ( "conversionService" ) && beanFactory. isTypeMatch ( "conversionService" , ConversionService . class ) ) {
beanFactory. setConversionService ( ( ConversionService ) beanFactory. getBean ( "conversionService" , ConversionService . class ) ) ;
}
if ( ! beanFactory. hasEmbeddedValueResolver ( ) ) {
beanFactory. addEmbeddedValueResolver ( ( strVal) -> {
return this . getEnvironment ( ) . resolvePlaceholders ( strVal) ;
} ) ;
}
String [ ] weaverAwareNames = beanFactory. getBeanNamesForType ( LoadTimeWeaverAware . class , false , false ) ;
String [ ] var3 = weaverAwareNames;
int var4 = weaverAwareNames. length;
for ( int var5 = 0 ; var5 < var4; ++ var5) {
String weaverAwareName = var3[ var5] ;
this . getBean ( weaverAwareName) ;
}
beanFactory. setTempClassLoader ( ( ClassLoader ) null ) ;
beanFactory. freezeConfiguration ( ) ;
beanFactory. preInstantiateSingletons ( ) ;
}
}
可以在上面进入后,看到这个:
List < String > beanNames = new ArrayList ( this . beanDefinitionNames) ;
if ( this . isFactoryBean ( beanName) ) {
bean = this . getBean ( "&" + beanName) ;
break ;
}
给上面的if (this.isFactoryBean(beanName)) {打上断点,然后点击这个:
只有满足条件的才是断点,所以到下一个断点就会到满足条件的那个地方,这个时候继续下一步:
if ( this . isFactoryBean ( beanName) ) {
bean = this . getBean ( "&" + beanName) ;
break ;
}
那么他是怎么配置成工厂bean的,或者说对应的名称是怎么处理工厂bean的,因为我们从来没有进行处理过,我们需要这对应的这个代码中打上断点:
beanName = var2. next ( ) ;
bd = this . getMergedLocalBeanDefinition ( beanName) ;
一般情况下,被识别成工厂bean,通常在于实现类实现了对应的工厂接口,通常是:
package org. springframework. beans. factory ;
import org. springframework. lang. Nullable ;
public interface FactoryBean < T > {
@Nullable
T getObject ( ) throws Exception ;
@Nullable
Class < ? > getObjectType ( ) ;
default boolean isSingleton ( ) {
return true ;
}
}
然后在xml中进行定义,创建对象实例,然后判断,当然,并不是必须要xml,因为这里是整合的,所以对应的大概率是注解生成
即对应的代理对象,应该是读取某个地方的注解,生成实例,通过判断是否实现了对应的接口FactoryBean,然后操作getObject返回实例,该返回的实例就是代理对象
但是中间也操作了bd = this.getMergedLocalBeanDefinition(beanName);,他干什么了,我们先看在名称为resumeDao时得到的值的显示:
Root bean: class [ org. springframework. data. jpa. repository. support. JpaRepositoryFactoryBean] ; scope= singleton; abstract = false ; lazyInit= false ; autowireMode= 0 ; dependencyCheck= 0 ; autowireCandidate= true ; primary= false ; factoryBeanName= null ; factoryMethodName= null ; initMethodName= null ; destroyMethodName= null
也就是:JpaRepositoryFactoryBean,虽然他是RootBeanDefinition类型的,但是对应的这个肯定与他有关系
我们进入bd = this.getMergedLocalBeanDefinition(beanName);(记得调试条件):
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory , BeanDefinitionRegistry , Serializable {
}
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
}
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
protected RootBeanDefinition getMergedLocalBeanDefinition ( String beanName) throws BeansException {
RootBeanDefinition mbd = ( RootBeanDefinition ) this . mergedBeanDefinitions. get ( beanName) ;
return mbd != null ? mbd : this . getMergedBeanDefinition ( beanName, this . getBeanDefinition ( beanName) ) ;
}
}
既然从集合里面拿取,那么什么时候放入的:
可以到关于this的进行全局搜索,一般就在AbstractBeanFactory里面可以找到mergedBeanDefinitions.put,发现在:
protected RootBeanDefinition getMergedBeanDefinition ( String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd) throws BeanDefinitionStoreException {
synchronized ( this . mergedBeanDefinitions) {
RootBeanDefinition mbd = null ;
if ( containingBd == null ) {
mbd = ( RootBeanDefinition ) this . mergedBeanDefinitions. get ( beanName) ;
}
}
在上面方法的里面,我们给RootBeanDefinition mbd = null;,加上断点,发现有String beanName,那么继续操作条件
当然,有很多操作会操作到这里,我们只看他进行第一次put的情况,我们继续观察,这个时候可以发现BeanDefinition bd中bd是有值的,所以需要看他调用栈来确定了,看这里:
我们进入方法:
public BeanDefinition getBeanDefinition ( String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = ( BeanDefinition ) this . beanDefinitionMap. get ( beanName) ;
if ( bd == null ) {
if ( this . logger. isTraceEnabled ( ) ) {
this . logger. trace ( "No bean named '" + beanName + "' found in " + this ) ;
}
throw new NoSuchBeanDefinitionException ( beanName) ;
} else {
return bd;
}
}
我们找他put方法:
public void registerBeanDefinition ( String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
Assert . hasText ( beanName, "Bean name must not be empty" ) ;
Assert . notNull ( beanDefinition, "BeanDefinition must not be null" ) ;
if ( beanDefinition instanceof AbstractBeanDefinition ) {
try {
( ( AbstractBeanDefinition ) beanDefinition) . validate ( ) ;
} catch ( BeanDefinitionValidationException var8) {
throw new BeanDefinitionStoreException ( beanDefinition. getResourceDescription ( ) , beanName, "Validation of bean definition failed" , var8) ;
}
}
}
在上面的 Assert.notNull(beanDefinition, “BeanDefinition must not be null”);打上断点并加上条件(有beanName),看调用栈:
我们看参数beanDefinition有值,且放入的map中就是他,那么看看调用栈中是谁先没有的:
我们继续看后面的调用栈:
上面考虑解析我们的自定义标签,一般来说,由于我们的标签存在自定义的,这里也就是jpa标签的,具体解析也由jpa来完成(spring可没有全部的解析过程,或者说解析器哦,这就需要框架来完成了),这里说明的标签一般就是:jpa:repositories
我们进入看看方法:
public class RepositoryConfigurationDelegate {
public List < BeanComponentDefinition > registerRepositoriesIn ( BeanDefinitionRegistry registry, RepositoryConfigurationExtension extension) {
if ( LOG . isInfoEnabled ( ) ) {
LOG . info ( "Bootstrapping Spring Data repositories in {} mode." , this . configurationSource. getBootstrapMode ( ) . name ( ) ) ;
}
extension. registerBeansForRoot ( registry, this . configurationSource) ;
RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder ( registry, extension, this . configurationSource, this . resourceLoader, this . environment) ;
List < BeanComponentDefinition > definitions = new ArrayList ( ) ;
StopWatch watch = new StopWatch ( ) ;
if ( LOG . isDebugEnabled ( ) ) {
LOG . debug ( "Scanning for repositories in packages {}." , this . configurationSource. getBasePackages ( ) . stream ( ) . collect ( Collectors . joining ( ", " ) ) ) ;
}
watch. start ( ) ;
Collection < RepositoryConfiguration < RepositoryConfigurationSource > > configurations = extension. getRepositoryConfigurations ( this . configurationSource, this . resourceLoader, this . inMultiStoreMode) ;
Map < String , RepositoryConfiguration < ? > > configurationsByRepositoryName = new HashMap ( configurations. size ( ) ) ;
Iterator var8 = configurations. iterator ( ) ;
while ( var8. hasNext ( ) ) {
RepositoryConfiguration < ? extends RepositoryConfigurationSource > configuration = ( RepositoryConfiguration ) var8. next ( ) ;
configurationsByRepositoryName. put ( configuration. getRepositoryInterface ( ) , configuration) ;
BeanDefinitionBuilder definitionBuilder = builder. build ( configuration) ;
extension. postProcess ( definitionBuilder, this . configurationSource) ;
if ( this . isXml) {
extension. postProcess ( definitionBuilder, ( XmlRepositoryConfigurationSource ) this . configurationSource) ;
} else {
extension. postProcess ( definitionBuilder, ( AnnotationRepositoryConfigurationSource ) this . configurationSource) ;
}
AbstractBeanDefinition beanDefinition = definitionBuilder. getBeanDefinition ( ) ;
String beanName = this . configurationSource. generateBeanName ( beanDefinition) ;
if ( LOG . isTraceEnabled ( ) ) {
LOG . trace ( "Spring Data {} - Registering repository: {} - Interface: {} - Factory: {}" , new Object [ ] { extension. getModuleName ( ) , beanName, configuration. getRepositoryInterface ( ) , configuration. getRepositoryFactoryBeanClassName ( ) } ) ;
}
beanDefinition. setAttribute ( "factoryBeanObjectType" , configuration. getRepositoryInterface ( ) ) ;
registry. registerBeanDefinition ( beanName, beanDefinition) ;
definitions. add ( new BeanComponentDefinition ( beanDefinition, beanName) ) ;
}
}
给上面的BeanDefinitionBuilder definitionBuilder = builder.build(configuration);打上断点,不需要条件(因为没不知道实使用什么条件)
BeanDefinitionBuilder builder = BeanDefinitionBuilder . rootBeanDefinition ( configuration. getRepositoryFactoryBeanClassName ( ) ) ;
public final class BeanDefinitionBuilder {
private final AbstractBeanDefinition beanDefinition;
}
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition , Cloneable {
}
public class RootBeanDefinition extends AbstractBeanDefinition {
}
然后我们进入configuration.getRepositoryFactoryBeanClassName():
public class DefaultRepositoryConfiguration < T extends RepositoryConfigurationSource > implements RepositoryConfiguration < T > {
public String getRepositoryFactoryBeanClassName ( ) {
return ( String ) this . configurationSource. getRepositoryFactoryBeanClassName ( ) . orElseGet ( ( ) -> {
return this . extension. getRepositoryFactoryBeanClassName ( ) ;
} ) ;
}
}
他是一个遍历,操作自定义的,所以最终我们会得到自定义的标签处理(考虑扫描的),最终也就是:
public String getRepositoryFactoryBeanClassName ( ) {
return JpaRepositoryFactoryBean . class . getName ( ) ;
}
得到自定义标签处理了,最终把这个返回,放入到对应的map中,也就是注册过程中进行了得到(自然也就会考虑名称),然后最终被我们得到,即:
BeanDefinition bd = ( BeanDefinition ) this . beanDefinitionMap. get ( beanName) ;
这样我们就得到了bean的信息了
简单来说:我们自定义标签后,spring让我们自行处理自定义的标签,我们的处理就是读取自定义标签信息,如包扫描,然后扫描到对应的接口,然后自定义一个实例信息用来进行创建实例,也就是说,对应的信息保存的不是接口或者类的全限定名,而是自定义或者说固定的,这里也就是:JpaRepositoryFactoryBean,那么根据这样的说明,本质上spring和mybatis的整合自然也是如此,当然了,单独的mybatis由于没有像spring的信息操作,所以他是单纯的搞个代理,而不是考虑spring信息的统一处理的,然后考虑代理,因为spring需要考虑很多地方的,而不是mybatis的单独一个
那么我们可以回到之前的这个地方了:
bd = this . getMergedLocalBeanDefinition ( beanName) ;
也就是说,他拿取的是我们固定的信息,即JpaRepositoryFactoryBean,操作实例时,自然考虑操作他,所以在后面的操作bean时(spring底层原理中有部分说明),会使用JpaRepositoryFactoryBean来操作创建bean,且判断是否为工厂对象也是判断他的,我们看这个:
public class JpaRepositoryFactoryBean < T extends Repository < S , ID> , S , ID> extends TransactionalRepositoryFactoryBeanSupport < T , S , ID> {
}
public abstract class TransactionalRepositoryFactoryBeanSupport < T extends Repository < S , ID> , S , ID> extends RepositoryFactoryBeanSupport < T , S , ID> implements BeanFactoryAware {
}
public abstract class RepositoryFactoryBeanSupport < T extends Repository < S , ID> , S , ID> implements InitializingBean , RepositoryFactoryInformation < S , ID> , FactoryBean < T > , BeanClassLoaderAware , BeanFactoryAware , ApplicationEventPublisherAware {
}
既然确定了得到信息的过程,那么在确定他是工厂的情况下,我们找到他的getObject方法,一般在他的父类的:
上面选择的是Show Inherited,代表显示继承的,一般有这个就可以全部看到了(因为实现的必须要自行写上的)
或者在电脑上按:ctrl+F12(如果是笔记本,可能需要加上fn来让F12生效)
我们进入:
public class JpaRepositoryFactoryBean < T extends Repository < S , ID> , S , ID> extends TransactionalRepositoryFactoryBeanSupport < T , S , ID> {
}
public abstract class TransactionalRepositoryFactoryBeanSupport < T extends Repository < S , ID> , S , ID> extends RepositoryFactoryBeanSupport < T , S , ID> implements BeanFactoryAware {
}
public abstract class RepositoryFactoryBeanSupport < T extends Repository < S , ID> , S , ID> implements InitializingBean , RepositoryFactoryInformation < S , ID> , FactoryBean < T > , BeanClassLoaderAware , BeanFactoryAware , ApplicationEventPublisherAware {
@Nonnull
public T getObject ( ) {
return ( Repository ) this . repository. get ( ) ;
}
public void afterPropertiesSet ( ) {
this . factory = this . createRepositoryFactory ( ) ;
this . factory. setQueryLookupStrategyKey ( this . queryLookupStrategyKey) ;
this . factory. setNamedQueries ( this . namedQueries) ;
this . factory. setEvaluationContextProvider ( ( QueryMethodEvaluationContextProvider ) this . evaluationContextProvider. orElseGet ( ( ) -> {
return QueryMethodEvaluationContextProvider . DEFAULT ;
} ) ) ;
this . factory. setBeanClassLoader ( this . classLoader) ;
this . factory. setBeanFactory ( this . beanFactory) ;
if ( this . publisher != null ) {
this . factory. addRepositoryProxyPostProcessor ( new EventPublishingRepositoryProxyPostProcessor ( this . publisher) ) ;
}
RepositoryFactorySupport var10001 = this . factory;
this . repositoryBaseClass. ifPresent ( var10001:: setRepositoryBaseClass ) ;
RepositoryFragments customImplementationFragment = ( RepositoryFragments ) this . customImplementation. map ( ( xva$0 ) -> {
return RepositoryFragments . just ( new Object [ ] { xva$0 } ) ;
} ) . orElseGet ( RepositoryFragments :: empty ) ;
RepositoryFragments repositoryFragmentsToUse = ( ( RepositoryFragments ) this . repositoryFragments. orElseGet ( RepositoryFragments :: empty ) ) . append ( customImplementationFragment) ;
this . repositoryMetadata = this . factory. getRepositoryMetadata ( this . repositoryInterface) ;
this . mappingContext. ifPresent ( ( it) -> {
it. getPersistentEntity ( this . repositoryMetadata. getDomainType ( ) ) ;
} ) ;
this . repository = Lazy . of ( ( ) -> {
return ( Repository ) this . factory. getRepository ( this . repositoryInterface, repositoryFragmentsToUse) ;
} ) ;
if ( ! this . lazyInit) {
this . repository. get ( ) ;
}
}
}
他为什么可以执行afterPropertiesSet方法,因为他实现了InitializingBean接口,在spring中在实例放入map前面需要实现一系列的方法,所以这里会实现,即:调用InitializingBean接口的afterPropertiesSet方法,所以会进行设置(提一下:spring初始化并不是构造方法,只是一个单纯来执行的方法)
我们给上面的这个打上断点:
this . repository = Lazy . of ( ( ) -> {
return ( Repository ) this . factory. getRepository ( this . repositoryInterface, repositoryFragmentsToUse) ;
} ) ;
直接进入到这里(是下面的,看清楚,记得跳出不相关的,以后和以前可能没有说明,这里说明一下,后面不说明了):
public abstract class RepositoryFactorySupport implements BeanClassLoaderAware , BeanFactoryAware {
public < T > T getRepository ( Class < T > repositoryInterface, RepositoryFragments fragments) {
if ( LOG . isDebugEnabled ( ) ) {
LOG . debug ( "Initializing repository instance for {}…" , repositoryInterface. getName ( ) ) ;
}
Assert . notNull ( repositoryInterface, "Repository interface must not be null!" ) ;
Assert . notNull ( fragments, "RepositoryFragments must not be null!" ) ;
RepositoryMetadata metadata = this . getRepositoryMetadata ( repositoryInterface) ;
RepositoryComposition composition = this . getRepositoryComposition ( metadata, fragments) ;
RepositoryInformation information = this . getRepositoryInformation ( metadata, composition) ;
this . validate ( information, composition) ;
Object target = this . getTargetRepository ( information) ;
ProxyFactory result = new ProxyFactory ( ) ;
result. setTarget ( target) ;
result. setInterfaces ( new Class [ ] { repositoryInterface, Repository . class , TransactionalProxy . class } ) ;
if ( MethodInvocationValidator . supports ( repositoryInterface) ) {
result. addAdvice ( new MethodInvocationValidator ( ) ) ;
}
result. addAdvice ( SurroundingTransactionDetectorMethodInterceptor . INSTANCE ) ;
result. addAdvisor ( ExposeInvocationInterceptor . ADVISOR ) ;
this . postProcessors. forEach ( ( processor) -> {
processor. postProcess ( result, information) ;
} ) ;
result. addAdvice ( new DefaultMethodInvokingMethodInterceptor ( ) ) ;
ProjectionFactory projectionFactory = this . getProjectionFactory ( this . classLoader, this . beanFactory) ;
result. addAdvice ( new RepositoryFactorySupport. QueryExecutorMethodInterceptor ( information, projectionFactory) ) ;
composition = composition. append ( RepositoryFragment . implemented ( target) ) ;
result. addAdvice ( new RepositoryFactorySupport. ImplementationMethodExecutionInterceptor ( composition) ) ;
T repository = result. getProxy ( this . classLoader) ;
if ( LOG . isDebugEnabled ( ) ) {
LOG . debug ( "Finished creation of repository instance for {}." , repositoryInterface. getName ( ) ) ;
}
return repository;
}
}
当然,在上面打上断点也可以,在这里:RepositoryInformation information = this.getRepositoryInformation(metadata, composition);
我们看看调试信息:
发现了没有,存在了SimpleJpaRepository:
public class SimpleJpaRepository < T , ID> implements JpaRepositoryImplementation < T , ID> {
}
也就是说,我们看到了对应在前面的代理类里面的信息,即SimpleJpaRepository,我们看看他怎么生成的
RepositoryInformation information = this . getRepositoryInformation ( metadata, composition) ;
protected Class < ? > getRepositoryBaseClass ( RepositoryMetadata metadata) {
return SimpleJpaRepository . class ;
}
然后借助这个:
ProxyFactory result = new ProxyFactory ( ) ;
来产生工厂,中间进行一些设置,有传递包含SimpleJpaRepository的信息,然后到这里:
T repository = result. getProxy ( this . classLoader) ;
他是最后的返回的,然后让对应的:
@Nonnull
public T getObject ( ) {
return ( Repository ) this . repository. get ( ) ;
}
这个来获取
那么我们进入前面的result.getProxy(this.classLoader);:
public Object getProxy ( @Nullable ClassLoader classLoader) {
return this . createAopProxy ( ) . getProxy ( classLoader) ;
}
protected final synchronized AopProxy createAopProxy ( ) {
if ( ! this . active) {
this . activate ( ) ;
}
return this . getAopProxyFactory ( ) . createAopProxy ( this ) ;
}
public AopProxy createAopProxy ( AdvisedSupport config) throws AopConfigException {
if ( ! config. isOptimize ( ) && ! config. isProxyTargetClass ( ) && ! this . hasNoUserSuppliedProxyInterfaces ( config) ) {
return new JdkDynamicAopProxy ( config) ;
} else {
Class < ? > targetClass = config. getTargetClass ( ) ;
if ( targetClass == null ) {
throw new AopConfigException ( "TargetSource cannot determine target class: Either an interface or a target is required for proxy creation." ) ;
} else {
return ( AopProxy ) ( ! targetClass. isInterface ( ) && ! Proxy . isProxyClass ( targetClass) ? new ObjenesisCglibAopProxy ( config) : new JdkDynamicAopProxy ( config) ) ;
}
}
}
经过调试,对应的是jdk动态代理,并且他是操作new JdkDynamicAopProxy(config),他是代理对象工厂,我们继续回到之前的:
public Object getProxy ( @Nullable ClassLoader classLoader) {
return this . createAopProxy ( ) . getProxy ( classLoader) ;
}
这次我们进入getProxy,也就是JdkDynamicAopProxy的getProxy方法:
public Object getProxy ( @Nullable ClassLoader classLoader) {
if ( logger. isTraceEnabled ( ) ) {
logger. trace ( "Creating JDK dynamic proxy: " + this . advised. getTargetSource ( ) ) ;
}
Class < ? > [ ] proxiedInterfaces = AopProxyUtils . completeProxiedInterfaces ( this . advised, true ) ;
this . findDefinedEqualsAndHashCodeMethods ( proxiedInterfaces) ;
return Proxy . newProxyInstance ( classLoader, proxiedInterfaces, this ) ;
}
最后我们返回,我们看看他的信息:
返回后的信息:
在代理中,对应的显示后面是toString的结果,但是也要注意:这通常是考虑invoke里面的,匿名得到的值(这很明显,基本是固定的返回),还有返回的这个代理,而h,则代表是使用那个类来完成这个创建的(相当于this),这里很明显是使用对应的工厂类,后面就是里面的一些设置的信息了(这些信息了解即可)
而拦截得到的结果是上面的return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);的this来处理的,那么他当前类肯定实现了InvocationHandler接口,即里面必然操作了invoke(不愧是代理工厂),里面肯定会返回对应的操作
至此:我们得到的T repository = result.getProxy(this.classLoader);中,就是一个拦截后,得到结果,注意是拦截后,也就是说,不拦截的情况下他自然是代理对象
最后对应的getObject就会得到这个值,因为:
this . repository = Lazy . of ( ( ) -> {
return ( Repository ) this . factory. getRepository ( this . repositoryInterface, repositoryFragmentsToUse) ;
} ) ;
上面设置了value属性,在getObject中:
return ( Repository ) this . repository. get ( ) ;
public T get ( ) {
T value = this . getNullable ( ) ;
if ( value == null ) {
throw new IllegalStateException ( "Expected lazy evaluation to yield a non-null value but got null!" ) ;
} else {
return value;
}
}
@Nullable
private T getNullable ( ) {
T value = this . value;
if ( this . resolved) {
return value;
} else {
value = this . supplier. get ( ) ;
this . value = value;
this . resolved = true ;
return value;
}
}
就返回了这个属性,所以最终得到了对应的T repository = result.getProxy(this.classLoader);
也就是说,通过getObject生成的代理对象交给ResumeDao接口赋值,然后这个接口作为代理对象的引用,在调用对应的方法时,将拦截产生的结果进行赋值,最终我们得到了对应的处理,如查询,新增,删除,修改等等
@Repository
@Transactional (
readOnly = true
)
public class SimpleJpaRepository < T , ID> implements JpaRepositoryImplementation < T , ID> {
}
@NoRepositoryBean
public interface JpaRepositoryImplementation < T , ID> extends JpaRepository < T , ID> , JpaSpecificationExecutor < T > {
void setRepositoryMethodMetadata ( CrudMethodMetadata var1) ;
default void setEscapeCharacter ( EscapeCharacter escapeCharacter) {
}
}
public interface ResumeDao extends JpaRepository < Resume , Long > ,
JpaSpecificationExecutor < Resume > {
}
当然,其ResumeDao接口里面自定义的接口方法,通常在前面spring让我们操作自定义标签时,会对其实例进行一些处理,当操作的是对应自身的接口方法时,对应的拦截产生的对象中,可能在产生过程会进行一些处理,使得SimpleJpaRepository可能会进行一些处理,在mybatis中是找到xml,读取sql,进行执行处理,将结果返回,然后我们得到,那么这里是继续读取名称或者注解,解析成sql后(自定义的部分,而不是其他的固定部分),执行sql,返回结果,即最终操作拦截后的返回,这样我们就得到了对应的查询,删除,修改,新增的结果了
但是考虑到返回结果的toString是SimpleJpaRepository的类型,那么大概率是在执行invoke方法时,传递的就是这个类,而这个类就实现了上面的对应方法,来完成拦截,如果是自定义的,那么可能是将sql作为参数传递,或者执行一些其他的方法,让该类进行处理得到结果,这里可以参照106章博客(因为在107章博客或者后面中只考虑增强,没有考虑返回,虽然mybatis的底层原理(106章博客)中考虑的返回是直接的结果,而非交给其他类执行(这里就是交给SimpleJpaRepository处理))
至此我们的Spring Data JPA源码解析说明完毕了,以后需要深入的时候,看看其他如注解的处理吧(前面的也是,如mybatis,spring,springmvc等等,都只是说明,而非深入)