定義 Repository 介面
若要定義 repository 介面,您首先需要定義特定於領域類別的 repository 介面。該介面必須擴展 `Repository` 並針對領域類別和 ID 類型進行類型化。如果您想為該領域類型公開 CRUD 方法,您可以擴展 `CrudRepository` 或其變體之一,而不是 `Repository`。
微調 Repository 定義
有幾種變體可以開始使用您的 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`。請注意,各種排序 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 list。
如果您的應用程式中的許多 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 尋找個別使用者,並觸發查詢以依電子郵件地址尋找 `Users`。
中間 repository 介面使用 `@NoRepositoryBean` 註解。請確保將該註解添加到 Spring Data 不應在執行時期建立實例的所有 repository 介面。 |
搭配多個 Spring Data 模組使用 Repositories
在您的應用程式中使用單一 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`)。
以下範例示範一個使用模組特定介面的 repository(在本例中為 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 模組的有效候選者。
以下範例示範一個使用泛型介面的 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 模組時沒有問題,但多個模組無法區分這些 repository 應該綁定到哪個特定的 Spring Data。
以下範例示範一個使用帶註解的領域類別的 repository
interface PersonRepository extends Repository<Person, Long> { … }
@Entity
class Person { … }
interface UserRepository extends Repository<User, Long> { … }
@Document
class User { … }
`PersonRepository` 參考了使用 JPA `@Entity` 註解的 `Person`,因此此 repository 明顯屬於 Spring Data JPA。`UserRepository` 參考了使用 Spring Data MongoDB 的 `@Document` 註解的 `User`。
以下不良範例示範一個使用帶有混合註解的領域類別的 repository
interface JpaPersonRepository extends Repository<Person, Long> { … }
interface MongoDBPersonRepository extends Repository<Person, Long> { … }
@Entity
@Document
class Person { … }
此範例示範一個領域類別同時使用 JPA 和 Spring Data MongoDB 註解。它定義了兩個 repository,`JpaPersonRepository` 和 `MongoDBPersonRepository`。一個用於 JPA,另一個用於 MongoDB 用途。Spring Data 無法再區分這些 repository,這會導致未定義的行為。
Repository 類型詳細資訊和區分領域類別註解用於嚴格的 repository 組態,以識別特定 Spring Data 模組的 repository 候選者。在同一個領域類型上使用多個特定於持久性技術的註解是可能的,並且可以跨多個持久性技術重複使用領域類型。但是,Spring Data 屆時將無法再確定要將 repository 綁定到的唯一模組。
區分 repository 的最後一種方法是透過劃定 repository 基礎套件的範圍。基礎套件定義了掃描 repository 介面定義的起點,這表示 repository 定義位於適當的套件中。預設情況下,註解驅動的組態使用組態類別的套件。基於 XML 的組態中的基礎套件是強制性的。
以下範例示範基礎套件的註解驅動組態
@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")
class Configuration { … }