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# 8.0和.NET Core 3.0高级编程 分享笔记二:编程基础第一部分
基础部分被我分为了2篇,因为实在太多了,但是每一个知识点我都不舍得删除,所以越写越多,这一篇博客整理了4个夜晚,内容有点多建议慢慢看.本章涵盖以下主题: 介绍C# 理解C#的基础知识 使用变量 处理空 ...
- python使用笔记25--深拷贝、浅拷贝
1.循环删除list 1 ll = [1,1,32,4,3,2,3,2,4,6,4,5,6,7,8] 2 for i in ll: 3 if i % 2 !=0: 4 ll.remove(i) 5 p ...
- 求数组的子数组之和的最大值IV
在之前的基础上又安排了二维数组的,在课上一开始是理解错要求了,简单的以为用循环数组就能解决,但是却忽视了子数组是否能构成矩形,之后课下和同学们讨论,主要是多重遍历,但是我还是没搞明白怎么构成新的二维数 ...
- war项目依赖war项目
还没有看,立个flag:https://my.oschina.net/u/588379/blog/1817077
- python基础之列表推导式
#列表推导式 ---> 返回的是列表 for语句 效率更高# 1*1 2*2 3*3 4*4 5*5 6*6 7*7 8*8 9*9# import time# to = time.clock( ...
- Linux CentOS 7 在Apache服务器上安装SSL证书
在开发微信小程序的时候,wx.request请求的地址必须是https的,所以只能重新配置服务器. 域名和服务器都是在阿里云上买的,系统是CentOS7,安装了Apache服务器.网上也找了一下,很多 ...
- 基于小熊派Hi3861鸿蒙开发的IoT物联网学习【二】
HarmonyOS内核开发-信号量开发案例学习记录 一.LiteOS里面的任务管理介绍: 任务状态通常分为以下四种: 就绪(Ready):该任务在就绪列表中,只等待CPU. 运行(Running) ...
- python开发包之pyecharts
一.python包国内源网址有: 阿里云 http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/ ...
- Java 中节省 90% 时间的常用的工具类
前言 你们有木有喜欢看代码的领导啊,我的领导就喜欢看我写的代码,有事没事就喜欢跟我探讨怎么写才最好,哈哈哈...挺好. 今天我们就一起来看看可以节省 90% 的加班时间的第三方开源库吧,第一个介绍的必 ...
- LAMP和LNMP环境搭建的艰辛历程
目录 1. LAMP环境的搭建 1. Apache 安装apache遇到的问题 2. mysql 登录mysql的方法 3. PHP 2. Lnmp环境的搭建 1. nginx 2. PHP 3. 配 ...