spring data repository 的核心抽象是 Repository 接口,这是一个泛型接口,主要的类型有两个,实体的类型,以及实体的 ID 的类型,使用时声明一个实现 Repository 的接口,并且声明需要的接口方法。其直接子接口有 CrudRepositoryListCrudRepository ,二者的区别在于返回查询结果,前者返回 Iterable 封装的查询结果,后者则是 List 。spring 提供了 Repository 丰富的子接口,从执行逻辑上的 PagingAndSortingRepositoryReactiveSortingRepository 到不同的存储 。如果这些没有符合使用场景的,你也可以通过 @RepositoryDefinition 进行自定义。因为声明接口之后还需要声明接口方法,如果需要多个类似的 Repository 可以声明一个 Repository 的父接口,通过对父接口注解 @NoRepositoryBean 避免 spring 自动创建其实现。

如果涉及到多个 spring-data 模块,比如 spring-data-jpa 和 spring-data-elasticsearch,spring 对大部分的数据源都使用 Repository 做抽象,为了区分一个特定的 Repository 定义和哪个存储关联,那么需要在领域类或者 Repository 接口的定义上指定,或者配置某种数据源适用的包的范围。

  • Repository 接口实现某种数据源 Repository 子接口,比如 JpaRepository
  • 领域类注解,例如 @Entity 表示属于 JPA,而 @Document 表示属于 MongoDB 或者 Elasticsearch
  • 配置数据源的适用范围, @EnableMongoRepositories(basePackages="com.example.mongo")

在 spring 的配置类上使用 @EnableXXXRepository 表达需要自动创建某类存储的 Repository 接口的代理( Repository 接口不需要自己实现,仅需要定义接口,实现将由 spring 自动创建)。查询方法是通过声明接口方法去声明的,spring-data-repository 定义了通过接口声明查询方法的一套规则,即本文开头提到的第二个链接中的内容。除了定义接口方法使 spring 自动创建查询之外,也可以自定义查询,使用 EnableJpaRepositories 中的 queryLookupStrategy 属性可以指定 CREATEUSE_DECLARED_QUERYCREATE_IF_NOT_FOUND

依据接口声明的方法和参数创建查询的方式支持大部分的使用场景,例如条件,顺序,分页等,集合或者流的返回形式,Null 检查,异步的返回形式。

Repository 还可以自动组合接口实现,如下:

interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {

  // Declare query methods here
}

CustomizedUserRepository 是一个接口,spring 在实现 UserRepository 时会查找 CustomizedUserRepository 的实现(需要遵守一定的命令规范,以 Impl 结尾,也可以使用 @EnableJpaRepositories(repositoryImplementationPostfix = "MyPostfix") 的配置指定),并进行组合。

spring-data-repository 支持 DDD 设计中的 aggregate root 的 event,以及 spring MVC 相关的特性,在前后端分离的设计方式中使用场景有限,不再赘述。