Spring Data JPA:解析SimpleJpaRepository
源码
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的更多相关文章
- spring data jpa 全面解析(实践 + 源码分析)
前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...
- 【spring boot 系列】spring data jpa 全面解析(实践 + 源码分析)
前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...
- Spring Data Jpa系列教程--------实体解析和关联关系
Spring Data Jpa是基于HIbernate开发的,所以建立实体建的实体和映射关系需要好好好的去了解一下,本文有以下内容,实体管理器介绍,实体与数据库表的映射介绍,关联关系(一对多,多对多) ...
- Spring Data JPA:解析CriteriaBuilder
源码 在Spring Data JPA相关的文章[地址]中提到了有哪几种方式可以构建Specification的实例,该处需要借助CriteriaBuilder,回顾一下Specification中t ...
- 快速搭建springmvc+spring data jpa工程
一.前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程,并提供了一个简单的demo作为参考. 二.创建maven工程 http://www.cnblo ...
- Spring Data JPA 入门Demo
什么是JPA呢? 其实JPA可以说是一种规范,是java5.0之后提出来的用于持久化的一套规范:它不是任何一种ORM框架,在我看来,是现有ORM框架在这个规范下去实现持久层. 它的出现是为了简化现有的 ...
- Spring Data JPA入门
1. Spring Data JPA是什么 它是Spring基于ORM框架.JPA规范封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作.它提供了包括增删改查等在内的常用功能, ...
- Spring Data JPA(官方文档翻译)
关于本书 介绍 关于这本指南 第一章 前言 第二章 新增及注意点 第三章 项目依赖 第四章 使用Spring Data Repositories 4.1 核心概念 4.2 查询方法 4.3 定义rep ...
- spring data jpa(一)
第1章 Spring Data JPA的快速入门 1.1 需求说明 Spring Data JPA完成客户的基本CRUD操作 1.2 搭建Spring Data JPA的开发环境 1. ...
- Spring Data JPA入门及深入
一:Spring Data JPA简介 Spring Data JPA 是 Spring 基于 ORM 框架.JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问 ...
随机推荐
- C#版Nebula客户端编译
一.需求背景 从Nebula的Github上可以发现,Nebula为以下语言提供了客户端SDK: nebula-cpp nebula-java nebula-go nebula-python nebu ...
- C语言:随机抽奖
#include <stdio.h> #include <stdlib.h> //<stdlib.h>用于调用 rand(), #include <time. ...
- excel带格式复制python
openpyxl 复制cell单元格包括所有样式 target_cell.data_type = source_cell.data_type target_cell.fill = copy(sourc ...
- ajax请求对返回数据data的处理
1,ajax请求会根据响应头的返回数据类型对返回的数据data变量进行不同的处理 $.get("data/user-permission-submit-" + ddo.manipu ...
- python之数据驱动ddt操作(方法一)
下载ddt并安装 Pip install ddt 或者官网下载安装 http://ddt.readthedocs.io/en/latest/ https://github.com/txels/ddt ...
- Python - list 列表常见方法
list.append(x) 介绍 在列表的末尾添加一个元素 相当于 a[len(a):] = [x] 返回值 None 栗子 # append a = [1, 2, 3] b = [4, 5, 6 ...
- kali操作系统添加中文输入法
今天一通操作真心累啊.想安装搜狗输入法,百度搜索了好多 三步走:https://blog.csdn.net/qq_44110340/article/details/101382732 一顿操作猛如虎, ...
- 第十篇 -- 下拉列表框QComboBox
效果图: ui_ComboBox.py # -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'ui ...
- Volitle
缓存一致性协议 最出名的是Intel的MESI协议,该协议保证了每个缓存中使用的共享变量的副本是一致的.其思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会 ...
- DC-6靶机
仅供个人娱乐 靶机信息 下载地址:https://download.vulnhub.com/dc/DC-6.zip 一.主机发现 nmap -sn 192.168.216.0/24 二.端口扫描 nm ...