定义Repository接口

2023年 3月 6日 31点热度 0人点赞

要定义Repository接口,您首先需要定义一个领域类特定的Repository接口。该接口必须继承 Repository 并且类型化为域类和 ID 类型。如果您想为该域类型暴露 CRUD 方法,您可以继承 CrudRepository 或其变体之一而不是 Repository。

微调Repository定义

您可以通过多种方式开始使用Repository接口。

典型的方法是扩展 CrudRepository,它为您提供 CRUD 功能的方法。CRUD 代表创建、读取、更新、删除。在 3.0 版中,我们还引入了 ListCrudRepository,它与 CrudRepository 非常相似,但对于那些返回多个实体的方法,它返回一个 List 而不是 Iterable,您可能会发现它更易于使用。

如果您使用的是reactive存储,您可以选择 ReactiveCrudRepository 或 RxJava3CrudRepository,具体取决于您使用的reactive框架。

如果你正在使用 Kotlin,你可能会选择 CoroutineCrudRepository,它利用了 Kotlin 的协程。

另外,如果您需要允许指定排序抽象或在第一种情况下指定分页抽象的方法,您可以扩展 PagingAndSortingRepository、ReactiveSortingRepository、RxJava3SortingRepository 或 CoroutineSortingRepository。请注意,各种排序Repository不再像在 Spring Data 3.0 之前的版本中那样扩展其各自的 CRUD Repository。因此,如果您需要两者的功能,则需要扩展这两个接口。

如果您不想扩展 Spring Data 接口,您还可以使用 @RepositoryDefinition 注解您的Repository接口。扩展其中一个 CRUD Repository接口会公开一组完整的方法来操作您的实体。如果您希望对公开的方法有选择性,请将要公开的方法从 CRUD Repository复制到您的域Repository中。这样做时,您可以更改方法的返回类型。如果可能,Spring Data 将遵循返回类型。例如,对于返回多个实体的方法,您可以选择 Iterable<T>、List<T>、Collection<T> 或 VAVR 列表。

如果您的应用程序中的许多Repository应该具有相同的一组方法,您可以定义自己的公共的基础接口来继承。这样的接口必须加上@NoRepositoryBean 注解。这可以防止 Spring Data 尝试直接创建它的实例并失败,因为它无法确定该Repository的实体,因为它仍然包含一个通用类型变量。

以下示例显示了如何有选择地公开 CRUD 方法(在本例中为 findById 和 save):

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends Repository<T, ID> {

  Optional<T> findById(ID id);

  <S extends T> S save(S entity);
}

interface UserRepository extends MyBaseRepository<User, Long> {
  User findByEmailAddress(EmailAddress emailAddress);
}

在前面的示例中,您为所有域Repository定义了一个公共基础接口,并公开了 findById(…) 和 save(…)。这些方法被路由到 Spring Data 提供的您选择的存储的基础Repository实现中( 例如,如果您使用 JPA,则实现是 SimpleJpaRepository),因为它们与 CrudRepository 中的方法签名匹配。所以 UserRepository 现在可以保存用户,通过 ID 查找单个用户,并触发查询以通过电子邮件地址查找用户。

中间Repository接口使用@NoRepositoryBean 注解。确保将该注解添加到 Spring Data 不应在运行时为其创建实例的所有Repository接口。

将Repository与多个 Spring 数据模块一起使用

在应用程序中使用唯一的 Spring Data 模块可以使事情变得简单,因为定义范围内的所有Repository接口都绑定到 Spring Data 模块。有时,应用程序需要使用多个 Spring Data 模块。在这种情况下,Repository定义必须区分持久性技术。当它在类路径上检测到多个Repository工厂时,Spring Data 进入严格的Repository配置模式。严格配置使用Repository或域类的详细信息来决定Repository定义的 Spring Data 模块绑定:

  • 如果Repository定义扩展了特定于模块的Repository,则它是特定 Spring Data 模块的有效候选者。
  • 如果域类使用特定于模块的类型注解进行注解,则它是特定 Spring Data 模块的有效候选者。Spring Data 模块接受第三方注解(例如 JPA 的 @Entity)或提供自己的注解(例如用于 Spring Data MongoDB 和 Spring Data Elasticsearch 的 @Document)。

以下示例显示了一个使用模块特定接口(在本例中为 JPA)的Repository:

interface MyRepository extends JpaRepository<User, Long> { }

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends JpaRepository<T, ID> { … }

interface UserRepository extends MyBaseRepository<User, Long> { … }

MyRepository 和 UserRepository 在它们的类型层次结构中扩展了 JpaRepository。它们是 Spring Data JPA 模块的有效候选者。

以下示例显示了一个使用通用接口的Repository:

interface AmbiguousRepository extends Repository<User, Long> { … }

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends CrudRepository<T, ID> { … }

interface AmbiguousUserRepository extends MyBaseRepository<User, Long> { … }

AmbiguousRepository 和 AmbiguousUserRepository 在其类型层次结构中仅扩展 Repository 和 CrudRepository。虽然这在使用唯一的 Spring Data 模块时很好,但是多个模块无法区分这些存储库应该绑定到哪个特定的 Spring Data。

以下示例显示了一个使用带注释的域类的存储库:

interface PersonRepository extends Repository<Person, Long> { … }

@Entity
class Person { … }

interface UserRepository extends Repository<User, Long> { … }

@Document
class User { … }

PersonRepository 引用 Person,它使用 JPA @Entity 注解进行注解,因此这个Repository显然属于 Spring Data JPA。UserRepository 引用 User,它使用 Spring Data MongoDB 的 @Document 注释进行注释。

以下错误示例显示了一个使用带有混合注释的域类的存储库:

interface JpaPersonRepository extends Repository<Person, Long> { … }

interface MongoDBPersonRepository extends Repository<Person, Long> { … }

@Entity
@Document
class Person { … }

此示例显示使用 JPA 和 Spring Data MongoDB 注释的域类。它定义了两个存储库,JpaPersonRepository 和 MongoDBPersonRepository。一个用于 JPA,另一个用于 MongoDB。Spring Data 不再能够区分存储库,这会导致未定义的行为。

Repository类型详细信息和区分领域类注解用于严格的Repository配置,以识别特定 Spring Data 模块的存储库候选者。在同一领域类型上使用多个持久性技术特定的注释是可能的,并且可以跨多个持久性技术重用域类型。但是,Spring Data 无法再确定用于绑定存储库的唯一模块。

区分存储库的最后一种方法是确定Repository基础包的范围。基础包定义了扫描存储库接口定义的起点,这意味着存储库定义位于适当的包中。默认情况下,注解驱动配置使用配置类的包。基于 XML 的配置中的基础包是必需的。

以下示例显示了基础包的注解驱动配置:

@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")
class Configuration { … }

rainbow

这个人很懒,什么都没留下

文章评论