定義倉庫介面
要定義倉庫介面,您首先需要定義一個特定於領域類的倉庫介面。該介面必須擴充套件 Repository
,並且需要指定領域類和 ID 型別。如果您想為該領域型別暴露 CRUD 方法,可以擴充套件 CrudRepository
或其變體之一,而不是 Repository
。
微調倉庫定義
您可以通過幾種不同的方式開始定義您的倉庫介面。
典型的方法是擴充套件 CrudRepository
,它提供了 CRUD 功能的方法。CRUD 代表建立(Create)、讀取(Read)、更新(Update)、刪除(Delete)。從 3.0 版本開始,我們還引入了 ListCrudRepository
,它與 CrudRepository
非常相似,但對於返回多個實體的方法,它返回 List
而不是 Iterable
,這可能更容易使用。
如果您使用響應式儲存,可以根據您使用的響應式框架選擇 ReactiveCrudRepository
或 RxJava3CrudRepository
。
如果您使用 Kotlin,可以選擇 CoroutineCrudRepository
,它利用了 Kotlin 的協程。
此外,如果您需要允許指定 Sort
抽象(或者在第一種情況下指定 Pageable
抽象)的方法,您可以擴充套件 PagingAndSortingRepository
、ReactiveSortingRepository
、RxJava3SortingRepository
或 CoroutineSortingRepository
。請注意,與 Spring Data 3.0 之前的版本不同,各種排序倉庫不再擴充套件其各自的 CRUD 倉庫。因此,如果您需要兩者的功能,則需要同時擴充套件這兩個介面。
如果您不想擴充套件 Spring Data 介面,也可以使用 `@RepositoryDefinition` 註解標記您的倉庫介面。擴充套件其中一個 CRUD 倉庫介面會暴露一組完整的方法來操作您的實體。如果您更傾向於選擇性地暴露方法,可以將您想從 CRUD 倉庫暴露的方法複製到您的領域倉庫中。這樣做時,您可以更改方法的返回型別。如果可能,Spring Data 將尊重返回型別。例如,對於返回多個實體的方法,您可以選擇 Iterable<T>
、List<T>
、Collection<T>
或 VAVR 列表。
如果應用程式中的許多倉庫應該擁有相同的方法集,您可以定義自己的基礎介面來繼承。這樣的介面必須使用 `@NoRepositoryBean` 進行註解。這會阻止 Spring Data 嘗試直接建立該介面的例項,從而避免因為無法確定該倉庫的實體(因為它仍然包含一個泛型型別變數)而導致失敗。
以下示例展示瞭如何選擇性地暴露 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);
}
在前面的示例中,您為所有領域倉庫定義了一個通用的基礎介面,並暴露了 findById(…)
和 save(…)
方法。這些方法會被路由到 Spring Data 提供的您選擇的儲存的基礎倉庫實現中(例如,如果您使用 JPA,實現是 SimpleJpaRepository
),因為它們匹配 CrudRepository
中的方法簽名。因此,UserRepository
現在可以儲存使用者,透過 ID 查詢單個使用者,並觸發查詢根據電子郵件地址查詢 Users
。
中間倉庫介面使用 `@NoRepositoryBean` 註解。請確保為所有 Spring Data 不應在執行時建立例項的倉庫介面新增此註解。 |
在多個 Spring Data 模組中使用倉庫
在應用程式中使用唯一的 Spring Data 模組會使事情變得簡單,因為定義範圍內的所有倉庫介面都繫結到該 Spring Data 模組。有時,應用程式需要使用不止一個 Spring Data 模組。在這種情況下,倉庫定義必須區分持久化技術。當在類路徑上檢測到多個倉庫工廠時,Spring Data 會進入嚴格倉庫配置模式。嚴格配置會使用倉庫或領域類的詳細資訊來決定倉庫定義的 Spring Data 模組繫結。
-
如果倉庫定義擴充套件了特定於模組的倉庫,則它是該特定 Spring Data 模組的有效候選者。
-
如果領域類使用特定於模組的型別註解進行註解,則它是該特定 Spring Data 模組的有效候選者。Spring Data 模組接受第三方註解(如 JPA 的 `@Entity`)或提供自己的註解(如 Spring Data MongoDB 和 Spring Data Elasticsearch 的 `@Document`)。
以下示例展示了一個使用特定於模組介面(本例中為 JPA)的倉庫
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 模組的有效候選者。
以下示例展示了一個使用通用介面的倉庫
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` 註解進行了註解,因此這個倉庫顯然屬於 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 無法再區分這些倉庫,這會導致未定義的行為。
在嚴格的倉庫配置中,倉庫型別詳情和區分領域類註解用於識別特定 Spring Data 模組的倉庫候選者。在同一領域型別上使用多個特定於持久化技術的註解是可能的,並且可以在多種持久化技術中重用領域型別。但是,Spring Data 隨後將無法確定唯一的模組來繫結倉庫。
區分倉庫的最後一種方法是根據倉庫基礎包(base package)進行限定範圍。基礎包定義了掃描倉庫介面定義的起始點,這意味著倉庫定義應位於相應的包中。預設情況下,註解驅動的配置使用配置類所在的包。XML 配置中的基礎包是強制性的。
以下示例展示了基礎包的註解驅動配置
@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")
class Configuration { … }