源码

SimpleJpaRepository的定义如下:

/**
* Default implementation of the {@link org.springframework.data.repository.CrudRepository} interface. This will offer
* you a more sophisticated interface than the plain {@link EntityManager} .
*
* @author Oliver Gierke
* @author Eberhard Wolff
* @author Thomas Darimont
* @author Mark Paluch
* @author Christoph Strobl
* @author Stefan Fussenegger
* @author Jens Schauder
* @author David Madden
* @author Moritz Becker
* @param <T> the type of the entity to handle
* @param <ID> the type of the entity's identifier
*/
@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {

解读:

SimpleJpaRepository实现了JpaRepositoryImplementation接口。

JpaRepositoryImplementation的定义如下:

/**
* SPI interface to be implemented by {@link JpaRepository} implementations.
*
* @author Oliver Gierke
* @author Stefan Fussenegger
* @author Jens Schauder
*/
@NoRepositoryBean
public interface JpaRepositoryImplementation<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> { /**
* Configures the {@link CrudMethodMetadata} to be used with the repository.
*
* @param crudMethodMetadata must not be {@literal null}.
*/
void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata); /**
* Configures the {@link EscapeCharacter} to be used with the repository.
*
* @param escapeCharacter Must not be {@literal null}.
*/
default void setEscapeCharacter(EscapeCharacter escapeCharacter) { }
}

解读:

JpaRepositoryImplementation接口继承了JpaSpecificationExecutor。

类图

调用链路

观察SimpleJpaRepository中findOne(Example<S> example)方法的实现,代码如下:

    /*
* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findOne(org.springframework.data.domain.Example)
*/
@Override
public <S extends T> Optional<S> findOne(Example<S> example) { try {
return Optional
.of(getQuery(new ExampleSpecification<S>(example, escapeCharacter), example.getProbeType(), Sort.unsorted())
.getSingleResult());
} catch (NoResultException e) {
return Optional.empty();
}
}

解读:

此方法由QueryByExampleExecutor接口定义。

观察SimpleJpaRepository中findOne(@Nullable Specification<T> spec)方法的实现,代码如下:

    /*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findOne(org.springframework.data.jpa.domain.Specification)
*/
@Override
public Optional<T> findOne(@Nullable Specification<T> spec) { try {
return Optional.of(getQuery(spec, Sort.unsorted()).getSingleResult());
} catch (NoResultException e) {
return Optional.empty();
}
}

解读:

此方法由JpaSpecificationExecutor接口定义。

小结:

上述两个findOne方法最终都是调用了如下getQuery方法:

    /**
* Creates a {@link TypedQuery} for the given {@link Specification} and {@link Sort}.
*
* @param spec can be {@literal null}.
* @param domainClass must not be {@literal null}.
* @param sort must not be {@literal null}.
* @return
*/
protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass, Sort sort) { CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<S> query = builder.createQuery(domainClass); Root<S> root = applySpecificationToCriteria(spec, domainClass, query);
query.select(root); if (sort.isSorted()) {
query.orderBy(toOrders(sort, root, builder));
} return applyRepositoryMethodMetadata(em.createQuery(query));
}

解读:

getQuery方法调用了applySpecificationToCriteria方法,该方法的实现如下:

    /**
* Applies the given {@link Specification} to the given {@link CriteriaQuery}.
*
* @param spec can be {@literal null}.
* @param domainClass must not be {@literal null}.
* @param query must not be {@literal null}.
* @return
*/
private <S, U extends T> Root<U> applySpecificationToCriteria(@Nullable Specification<U> spec, Class<U> domainClass,
CriteriaQuery<S> query) { Assert.notNull(domainClass, "Domain class must not be null!");
Assert.notNull(query, "CriteriaQuery must not be null!"); Root<U> root = query.from(domainClass); if (spec == null) {
return root;
} CriteriaBuilder builder = em.getCriteriaBuilder();
Predicate predicate = spec.toPredicate(root, query, builder); if (predicate != null) {
query.where(predicate);
} return root;
}

解读:

applySpecificationToCriteria方法调用了Specification的toPredicate方法,该方法是一个抽象方法,其定义如下:

    /**
* Creates a WHERE clause for a query of the referenced entity in form of a {@link Predicate} for the given
* {@link Root} and {@link CriteriaQuery}.
*
* @param root must not be {@literal null}.
* @param query must not be {@literal null}.
* @param criteriaBuilder must not be {@literal null}.
* @return a {@link Predicate}, may be {@literal null}.
*/
@Nullable
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);

解读:

纵观前述调用过程可知,此处Specification的toPredicate方法由findOne方法传递给getQuery方法的参数对应的类实现。

从findOne(Example<S> example)的实现可知,toPredicate方法由参数new ExampleSpecification<S>(example, escapeCharacter)对应ExampleSpecification类实现。

ExampleSpecification

由前面的类图可知,ExampleSpecification是SimpleJpaRepository的内部类,其定义如下:

    /**
* {@link Specification} that gives access to the {@link Predicate} instance representing the values contained in the
* {@link Example}.
*
* @author Christoph Strobl
* @since 1.10
* @param <T>
*/
private static class ExampleSpecification<T> implements Specification<T> { private static final long serialVersionUID = 1L; private final Example<T> example;
private final EscapeCharacter escapeCharacter; /**
* Creates new {@link ExampleSpecification}.
*
* @param example
* @param escapeCharacter
*/
ExampleSpecification(Example<T> example, EscapeCharacter escapeCharacter) { Assert.notNull(example, "Example must not be null!");
Assert.notNull(escapeCharacter, "EscapeCharacter must not be null!"); this.example = example;
this.escapeCharacter = escapeCharacter;
} /*
* (non-Javadoc)
* @see org.springframework.data.jpa.domain.Specification#toPredicate(javax.persistence.criteria.Root, javax.persistence.criteria.CriteriaQuery, javax.persistence.criteria.CriteriaBuilder)
*/
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return QueryByExamplePredicateBuilder.getPredicate(root, cb, example, escapeCharacter);
}
}

解读:

ExampleSpecification实现了Specification接口中的toPredicate方法。

小结:

如果需要调用SimpleJpaRepository的findOne方法,需要构造Specification或者Example对应的实例。

示例:

以匿名内部类的形式构造Specification对应的实例

    Specification<User> specification = new Specification<>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Path<Integer> path = root.get("id");
return cb.lt(path, id);
}
};

Note:

有如下一些方法调用了getQuery方法

Spring Data JPA:解析SimpleJpaRepository的更多相关文章

  1. spring data jpa 全面解析(实践 + 源码分析)

    前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...

  2. 【spring boot 系列】spring data jpa 全面解析(实践 + 源码分析)

    前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...

  3. Spring Data Jpa系列教程--------实体解析和关联关系

    Spring Data Jpa是基于HIbernate开发的,所以建立实体建的实体和映射关系需要好好好的去了解一下,本文有以下内容,实体管理器介绍,实体与数据库表的映射介绍,关联关系(一对多,多对多) ...

  4. Spring Data JPA:解析CriteriaBuilder

    源码 在Spring Data JPA相关的文章[地址]中提到了有哪几种方式可以构建Specification的实例,该处需要借助CriteriaBuilder,回顾一下Specification中t ...

  5. 快速搭建springmvc+spring data jpa工程

    一.前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程,并提供了一个简单的demo作为参考. 二.创建maven工程 http://www.cnblo ...

  6. Spring Data JPA 入门Demo

    什么是JPA呢? 其实JPA可以说是一种规范,是java5.0之后提出来的用于持久化的一套规范:它不是任何一种ORM框架,在我看来,是现有ORM框架在这个规范下去实现持久层. 它的出现是为了简化现有的 ...

  7. Spring Data JPA入门

    1. Spring Data JPA是什么 它是Spring基于ORM框架.JPA规范封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作.它提供了包括增删改查等在内的常用功能, ...

  8. Spring Data JPA(官方文档翻译)

    关于本书 介绍 关于这本指南 第一章 前言 第二章 新增及注意点 第三章 项目依赖 第四章 使用Spring Data Repositories 4.1 核心概念 4.2 查询方法 4.3 定义rep ...

  9. spring data jpa(一)

    第1章     Spring Data JPA的快速入门 1.1   需求说明 Spring Data JPA完成客户的基本CRUD操作 1.2   搭建Spring Data JPA的开发环境 1. ...

  10. Spring Data JPA入门及深入

    一:Spring Data JPA简介 Spring Data JPA 是 Spring 基于 ORM 框架.JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问 ...

随机推荐

  1. Hive源码上手及问题解决

    一.编译准备 1.下载源码包 https://github.com/apache/hive/archive/refs/tags/rel/release-2.3.7.zip 或使用git直接拉取 无法解 ...

  2. Rust安装-运行第一个程序-hello_world

    Rust官网:https://rust-lang.org/ 安装 点击install,选择版本 选择相对应的版本进行下载 我这里下载的是windows系统,运行下载好的exe文件,根据需要选择选对应的 ...

  3. [刘阳Java]_Spring AOP注解详细介绍_第8讲

    这节内容非常关键,我们会比较详细地介绍Spring AOP注解的使用 1. 要使用Spring AOP注解,必须满足如下的事项 导入Aspectj的jar.Spring3.0-AOP.jar.aopa ...

  4. Python+Request库+第三方平台实现验证码识别示例

    1.登录时经常的出现验证码,此次结合Python+Request+第三方验证码识别平台(超级鹰识别平台) 2.首先到超级鹰平台下载对应语言的识别码封装,超级鹰平台:http://www.chaojiy ...

  5. Lesson 12 Life on a desert island

    Lesson 12 Life on a desert island desert island ['dezət 'ailənd] n. 荒岛 uninhabited island coral isla ...

  6. Kafka之--多zookeeper,多broker之搭建

    闲来如事,突发兴趣倒腾一下了kafka.其实类似环境搭建的博客很多,我这里算是整合一下,另外写出自己的过程与看法.完整的过程如下: 1)先准备好3台服务器.我准备的机器hostname/ip为: ka ...

  7. 什么是TCP?什么是TCP协议?

    一.什么是TCP >>>TCP是一种传输控制协议,是面向连接的.可靠的.基于字节流之间的传输层通信协议 >>>在因特网协议族里面,TCP层是在IP层上面,应用层下面 ...

  8. POJ1934 Trip 题解

    LCS 模板,但要输出具体方案,这就很毒瘤了. 神奇的预处理:fa[i][j]表示在 \(a\) 串的前 \(i\) 个字符中,字母表第 \(j\) 个字母最晚出现的位置,fb[i][j]同理. 这样 ...

  9. SSM框架中mapper层,增删改查,如何实现

    1.批量修改 <!-- 批量修改 MySQL--> <update id="updateBatch" parameterType="java.lang. ...

  10. Python - 可变和不可变对象

    前置知识 在 Python 中,一切皆为对象 Python 中不存在值传递,一切传递的都是对象的引用,也可以认为是传址 有哪些可变对象,哪些不可变对象? 不可变对象:字符串.元组.数字(int.flo ...