源码

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. C# 8.0和.NET Core 3.0高级编程 分享笔记三:控制流程和转换类型

    控制流程和转换类型 本章的内容主要包括编写代码.对变量执行简单的操作.做出决策.重复执行语句块.将变量或表达式值从一种类型转换为另一种类型.处理异常以及在数值变量中检查溢出. 本章涵盖以下主题: 操作 ...

  2. vue3 script setup 定稿

    vue script setup 已经官宣定稿.本文主要翻译了来自 0040-script-setup 的内容. 摘要 在单文件组件(SFC)中引入一个新的 <script> 类型 set ...

  3. 在Ubuntu20中安装Elasticsearch和Kibana6.8.1版本 母胎教学

    首先,我们在Ubuntu中安装Elasticsearch6.8.1命令如下: $ docker pull elasticsearch:6.8.1 拉取完成后,创建Elasticsearch6.8.1容 ...

  4. PyVista:一款Python的三维可视化软件

    技术背景 三维可视化是一项在工业领域中非常重要的技术,而Python中最热门的可视化工具matplotlib和plotly,更加倾向于在数据领域的可视化,用于展现数据的结果.类似的还有百度的pyech ...

  5. Scala学习——基础入门

    基础语法 1)注意点 1)区分大小写 -  Scala是大小写敏感的,这意味着标识Hello 和 hello在Scala中会有不同的含义. 2)类名 - 对于所有的类名的第一个字母要大写. 3)方法名 ...

  6. 03 高性能IO模型:采用多路复用机制的“单线程”Redis

    本篇重点 三个问题: "Redis真的只有单线程吗?""为什么用单线程?""单线程为什么这么快?" "Redis真的只有单线程吗? ...

  7. R在ubuntu16.04上环境搭建

    1.R安装 sudo apt-get update sudo apt-get remove vim-common sudo apt-get install vimapt-cache show r-ba ...

  8. 【LeetCode】94. 二叉树的中序遍历

    94. 二叉树的中序遍历 知识点:二叉树:递归:Morris遍历 题目描述 给定一个二叉树的根节点 root ,返回它的 中序 遍历. 示例 输入:root = [1,null,2,3] 输出:[1, ...

  9. P5042 丢失的题面

    P5042 丢失的题面 顺序:10 - 1 - 7 - 8 - 9 - 4 - 5 - 6 - 2 - 3 Point 10 读入,特判,输出. 读入的英文意思是让选手输出自己的程序本身,这个题的确存 ...

  10. Python 接口之request ,headers格式不对

    复制heardes格式,模拟请求报错 原因:粗心,headers带了空格