源码

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. 计算机网络体系结构整理-第九单元移动IP

    第九章 移动IP 什么是移动:移动指的是用户连接位置的改变,而不是设备物理位置的改变 移动可以是离散的或连续的 移动IP的基本要求:1.IP地址不变 2.宿地址路由 3.信息量和交互简化 4.安全 5 ...

  2. WPF教程二:理解WPF的布局系统和常用的Panel布局

    WPF的布局系统 了解元素的测量和排列方式是理解布局的第一步.在测量(measure)阶段容器遍历所有子元素,并询问子元素它们所期望的尺寸.在排列(arrange)阶段,容器在合适的位置放置子元素.理 ...

  3. python 字符串 增、删、改、查基本操作

    private static String TAG = "MainActivity"; private String str = " a,bB,1cCcc,2dDd d2 ...

  4. mybatis复杂映射

    1. 类型名对应 当实体类与表中字段完全一致时,mapper文件里返回类型用resultType,否则要用resultMap,并且建立resultMap映射 package com.rf.domain ...

  5. 「 题解」NOIP2021模拟赛(2021-07-19)

    小兔的话 欢迎大家在评论区留言哦~ D - 矩阵 简单题意 一个 \(i * i\) 的 \(01\) 矩阵,若满足 每一行 和 每一列 都满足 恰好 有 \(2\) 个位置是 \(1\) 时,称为 ...

  6. java02实验:方法

    一:素数输出 1.实验要求: (1)编写判断该数是否为素数的方法,并在主方法中对其进行调用. (2)注意编程规范:程序开头部分的目的,作者以及日期:必要的空格与缩进,适当的注释等: (3)实验报告中要 ...

  7. vue实现menu菜单懒加载

    本文将在vue+element ui项目中简单实现menu菜单的懒加载. 最近接到这样的需求:菜单的选项不要固定的,而是下一级菜单选项需要根据上级菜单调接口来获取.what? 这不就是懒加载吗?翻了一 ...

  8. python + pytest基本使用方法(运行测试&测试报告)

    import pytest# 1.运行名称中包含某字符串的测试用例#名称中含add 的测试用例# 执行: pytest -k add test_assert.py# 2.减少测试的运行冗长# 执行: ...

  9. Maven BOM!拿来吧你

    what BOM? BOM(Bill of Materials)是由Maven提供的功能,它通过定义一整套相互兼容的jar包版本集合, 使用时只需要依赖该BOM文件,即可放心的使用需要的依赖jar包, ...

  10. dos命令的学习

    打开CMD的方式 开始+系统+命令提示符 Windows+R+输入CMD 在任意的文件夹下面,按住shift+点击鼠标右键,在此处打开命令行窗口 资源管理器的地址栏前面加上CMD路径 管理员方式运行: ...