Spring Data JPA:解析JpaSpecificationExecutor & Specification
源码
在前面关于SimpleJpaRepository的文章[地址]中可以得知,SimpleJpaRepository间接实现了JpaSpecificationExecutor接口,本文就详细探究一下该接口。
JpaSpecificationExecutor的定义如下:
/**
* Interface to allow execution of {@link Specification}s based on the JPA criteria API.
*
* @author Oliver Gierke
* @author Christoph Strobl
*/
public interface JpaSpecificationExecutor<T> { /**
* Returns a single entity matching the given {@link Specification} or {@link Optional#empty()} if none found.
*
* @param spec can be {@literal null}.
* @return never {@literal null}.
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one entity found.
*/
Optional<T> findOne(@Nullable Specification<T> spec); /**
* Returns all entities matching the given {@link Specification}.
*
* @param spec can be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(@Nullable Specification<T> spec); /**
* Returns a {@link Page} of entities matching the given {@link Specification}.
*
* @param spec can be {@literal null}.
* @param pageable must not be {@literal null}.
* @return never {@literal null}.
*/
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable); /**
* Returns all entities matching the given {@link Specification} and {@link Sort}.
*
* @param spec can be {@literal null}.
* @param sort must not be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(@Nullable Specification<T> spec, Sort sort); /**
* Returns the number of instances that the given {@link Specification} will return.
*
* @param spec the {@link Specification} to count instances for. Can be {@literal null}.
* @return the number of instances.
*/
long count(@Nullable Specification<T> spec);
}
解读:
上述接口提供了一个findOne方法以及三个接受不同参数的findAll方法,这几个方法接受Specification类型的参数
示例
在实际开发中,通常按如下示例中展示的方式使用JpaSpecificationExecutor接口
Repository层:
@Repository
public interface UserRepository extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> { }
Service层:
public Page<User> getUsers(Integer id, Integer pageNum, Integer pageSize) {
Sort sort = Sort.by(Sort.Direction.DESC, "id");
Pageable pageable = PageRequest.of(pageNum, pageSize, sort);
Specification<User> specification = (Specification<User>) (root, query, cb) -> {
Path<Integer> path = root.get("id");
return cb.lt(path, id);
};
return userRepository.findAll(specification, pageable);
}
解读:
此处Service调用了userRepository的findAll方法,参数为Specification的实例以及Pageable的实例,该findAll方法实质上是JpaSpecificationExecutor提供的findAll方法
Specification
从本文前面的描述得知,在调用JpaSpecificationExecutor接口提供的几个方法时需要构造Specification类型的参数。
在前面关于SimpleJpaRepository的文章[地址]中提到了构造Specification类型参数的方式:匿名内部类或者ExampleSpecification的实例,本小节来剖析一下Specification的细节。
类图

解读:
从类图可知,ByIdsSpecification、ExampleSpecification实现了Specification接口
进一步发掘,可以发现ByIdsSpecification、ExampleSpecification都是SimpleJpaRepository的内部类,如下图所示:

源码
Specification定义在包路径org.springframework.data.jpa.domain下,其定义如下:
/**
* Specification in the sense of Domain Driven Design.
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Krzysztof Rzymkowski
* @author Sebastian Staudt
* @author Mark Paluch
* @author Jens Schauder
*/
public interface Specification<T> extends Serializable { long serialVersionUID = 1L; /**
* Negates the given {@link Specification}.
*
* @param <T> the type of the {@link Root} the resulting {@literal Specification} operates on.
* @param spec can be {@literal null}.
* @return guaranteed to be not {@literal null}.
* @since 2.0
*/
static <T> Specification<T> not(@Nullable Specification<T> spec) { return spec == null //
? (root, query, builder) -> null //
: (root, query, builder) -> builder.not(spec.toPredicate(root, query, builder));
} /**
* Simple static factory method to add some syntactic sugar around a {@link Specification}.
*
* @param <T> the type of the {@link Root} the resulting {@literal Specification} operates on.
* @param spec can be {@literal null}.
* @return guaranteed to be not {@literal null}.
* @since 2.0
*/
static <T> Specification<T> where(@Nullable Specification<T> spec) {
return spec == null ? (root, query, builder) -> null : spec;
} /**
* ANDs the given {@link Specification} to the current one.
*
* @param other can be {@literal null}.
* @return The conjunction of the specifications
* @since 2.0
*/
default Specification<T> and(@Nullable Specification<T> other) {
return SpecificationComposition.composed(this, other, CriteriaBuilder::and);
} /**
* ORs the given specification to the current one.
*
* @param other can be {@literal null}.
* @return The disjunction of the specifications
* @since 2.0
*/
default Specification<T> or(@Nullable Specification<T> other) {
return SpecificationComposition.composed(this, other, CriteriaBuilder::or);
} /**
* 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);
}
解读:
其中只有toPredicate方法抽象方法,所以通过匿名内部类的形式构造Specification的实例时只需实现toPredicate方法即可。
Root、Path
Specification中toPredicate方法的的第一个参数为Root<T> root,前面示例的Service层在实现toPredicate方法时通过调用如下语句获得Path类型的变量
Path<Integer> path = root.get("id");
下图展示了Root、Path之间的关系:

解读:
从上图可知,Root接口间接继承了Path接口,前述调用语句中的get方法由Path接口定义

相关代码如下:
<Y> Path<Y> get(String attributeName);
参加[官方Doc]
Spring Data JPA:解析JpaSpecificationExecutor & Specification的更多相关文章
- spring data jpa封装specification实现简单风格的动态查询
github:https://github.com/peterowang/spring-data-jpa-demo 单一实体的动态查询: @Servicepublic class AdvancedUs ...
- Spring Data JPA教程, 第四部分: JPA Criteria Queries(未翻译)
The third part of my Spring Data JPA tutorialdescribed how you can create custom queries by using qu ...
- Spring Data Jpa:分页、Specification、Criteria
分页的主要接口与类 PagingAndSortingRepository 继承自 CrudRepository 接口,提供了排序以及分页查询能力,提供了两个方法 Iterable<T> f ...
- spring data jpa 全面解析(实践 + 源码分析)
前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...
- Spring data jpa 实现简单动态查询的通用Specification方法
本篇前提: SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法 这篇文章中的第二种方法 实现Specification 这块的方法 只适用于一个对象针对某一个固定字 ...
- 【spring boot 系列】spring data jpa 全面解析(实践 + 源码分析)
前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...
- 使用Spring Data JPA的Specification构建数据库查询
Spring Data JPA最为优秀的特性就是可以通过自定义方法名称生成查询来轻松创建查询SQL.Spring Data JPA提供了一个Repository编程模型,最简单的方式就是通过扩展Jpa ...
- Spring Data JPA:解析SimpleJpaRepository
源码 SimpleJpaRepository的定义如下: /** * Default implementation of the {@link org.springframework.data.rep ...
- Spring Data JPA:解析CriteriaBuilder
源码 在Spring Data JPA相关的文章[地址]中提到了有哪几种方式可以构建Specification的实例,该处需要借助CriteriaBuilder,回顾一下Specification中t ...
- Spring Data Jpa系列教程--------实体解析和关联关系
Spring Data Jpa是基于HIbernate开发的,所以建立实体建的实体和映射关系需要好好好的去了解一下,本文有以下内容,实体管理器介绍,实体与数据库表的映射介绍,关联关系(一对多,多对多) ...
随机推荐
- Java 将Word转为Tiff
本文以Java代码示例展示如何将Word文档转换为Tiff格式.代码方法比较简单,加载Word文档,并通过saveToTiff(tiffFilename)方法直接保存为tiff格式即可. 1.Java ...
- debug:am trace-ipc源码分析
debug:am trace-ipc源码分析 目录 debug:am trace-ipc源码分析 一.使用 官网介绍 命令提示 小结 二.源码分析 ActivityManagerShellComman ...
- map 和 unordered_map
map就是映射. 定义 map<typename,typename> 注:map的元素是pair. 特性 map会对第一个对象自动排序. map不允许有两个相同的关键字. map可以定义迭 ...
- Linux虚拟机与主机网络连接配置与文件传输
网络配置 对于VMware虚拟机 1. 设置linux系统的网络配置,如下(NAT为默认配置,这里采用这一配置) 2. 主机中配置本地连接-属性-共享-勾选红框配置项,如下: 3.重启虚拟机. ...
- Python -- 值转换为字符串的两种机制
可以通过以下两个函数来使用这两种机制:一是通过str函数,它会把值转换为合理形式的字符串,以便用户可以理解:而repr会创建一个字符串,它以合法的Python表达式的形式来表示值.下面是一些例子: & ...
- Intouch 关于报表数据的一种思路
在熟悉Intouch项目有一段时间了,也做有相关的三个项目,关于Intouch的一些报表数据的采集,也有了自己一定的看法(主要还是因为自己是野路子)今天就把我常用的一种制作思路,提供给大家.(仅供参考 ...
- ifix 在切换菜单按钮弹出”已打开该画面“bug修复
在ifix项目中,实际上会用到点击按钮弹出按钮菜单,点击另一按钮弹出另一按钮菜单的情况.一般在使用过程中切换菜单可有如下两种普遍做法: 1.使用ClosePicture "Middle&qu ...
- koa踩坑记录
1.koa热更新用nodemon 2.koa中暂不支持import/export 3.只发送options请求,没有后续请求 当ctx.set('Access-Control-Allow-Cred ...
- OpenGL学习笔记(四)纹理
目录 要完成的纹理效果 纹理环绕方式 纹理过滤 多级渐远纹理 加载与创建纹理 stb_image库的使用方法 生成纹理对象 应用纹理 纹理单元 参考资料:OpenGL中文翻译 要完成的纹理效果 纹理是 ...
- Java8 新特性 Stream Api 之集合遍历
前言 随着java版本的不断更新迭代,java开发也可以变得甜甜的,最新版本都到java11了,但是后面版本也是不在提供商用支持,需要收费,但是java8 依然是持续免费更新使用的,后面版本也更新很快 ...