504
人物
《Spring Data實戰》——2.3 定義Repository
本節書摘來自異步社區《Spring Data實戰》一書中的第2章,第2.3節,作者: 【美】Mark Pollack , Oliver Gierke , Thomas Risberg , Jon Brisbin , Michael Hunger著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看
2.3 定義Repository
到目前為止,我們看到了帶有查詢方法的Repository接口,這些查詢有的是從方法名中衍生出來的,有的是手動聲明的,這取決於Spring Data為實際存儲類型所提供的使用方式。為了衍生出這些查詢,我們必須擴展Spring Data的特定標識接口:Repository。除了查詢以外,在你的Repository中還需要一些其他的功能:存儲對象,刪除對象,根據ID進行查找,返回所有存儲的實體或按頁對它們進行訪問。通過Repository接口來暴露這些功能的最簡單方式就是使用一個Spring Data所提供的更為高級的Repository接口。
Repository
一個簡單的標識接口,允許Spring Data的基礎設施獲取用戶定義的Repository。
CrudRepository
擴展自Repository並添加了基本的持久化方法如對實體的保存、查找以及刪除。
PagingAndSortingRepositories
擴展自CrudRepository並添加了按頁訪問實體以及根據給定的條件(criteria)進行排序的方法。
假設我們想讓CustomerRepository暴露基本的CRUD方法,所需要做就是修改其聲明,如示例2-12所示。
示例2-12 暴露CRUD方法的CustomerRepository
CrudRepository接口如示例2-13所示。它包括了保存單個實體以及多個Iterable實體的方法、獲取單個實體或所有實體的方法以及不同形式的delete(...)方法。
示例2-13 CrudRepository
支持Repository方式的每個Spring Data模塊都提供了這個接口的實現。因此,我們聲明的命名空間元素會觸發基礎設施,這些設施不僅會啟動那些用於執行查詢方法的合適代碼,同時還會使用一個通用Repository實現類的實例來在背後執行CrudRepository中所聲明的方法,最終會將save(...)、findAll()等方法的調用委托給該實例。PagingAndSortingRepository(如示例2-14所示)擴展了CrudRepository並為通用的findAll(...)添加了處理Pageable和Sort實例的方法,從而能夠實現逐頁訪問實體。
示例2-14 PagingAndSortingRepository
要將這些功能引入到CustomerRepository中,隻需簡單地擴展PagingAndSorting Repository來取代CrudRepository即可。
2.3.1 調整Repository接口
正如我們在前麵所見,通過擴展合適的Spring Data接口,可以很容易地引入大量預先定義的功能。這種級別的粒度實際上是一種權衡,那就是如果為所有的查找方法、所有的保存方法等都定義單獨的接口,我們會暴露接口的數量(以及因此導致的複雜性)以及開發人員使用的便利性之間的權衡。
但是,可能會有這樣的場景,那就是隻想暴露讀方法(CRUD中的R)或者隻想在Repository接口中將刪除方法屏蔽掉。如今,Spring Data允許定義個性化的基礎Repository,隻需按照以下的步驟操作即可。
1.創建一個接口,這個接口要麼擴展自Repository,要麼添加@RepositoryDefinition注解。
2.添加想要暴露的方法並確保它們與Spring Data基礎Repository接口所提供的方法簽名相同。
3.對於實體所對應的接口聲明,要使用這個接口作為基礎接口。
為了闡述這一點,假設我們隻想暴露接收Pageable的findAll(...)方法以及save方法。這個基礎接口看起來可能如示例2-15所示。
示例2-15 自定義基礎Repository接口
需要注意的一點是我們為這個接口添加了一個額外的注解@NoRepositoryBean,從而確保Spring Data Repository的基礎設施不會試圖為其創建Bean的實例。讓CustomerRepository擴展這個接口就能精確做到隻暴露你所定義的API。
接下來可以定義出各種基本的接口(如ReadOnlyRepository或SaveOnlyRepository)甚至組成它們的繼承體係,這取決於項目的需要。通常建議本地定義的CRUD方法在開始的時候直接位於每個實體的具體Repository中,必要的話,再將它們要麼轉移到Spring Data提供的基礎Repository中,要麼轉移到特製的Repository中。按照這種方式,可以保證隨著項目複雜性的增長,構件(artifact)的數量能夠自然地增長。
2.3.2 手動實現Repository方法
到目前為止,看到了兩種類型的Repository方法:CRUD方法和查詢方法。每種類型都是由Spring Data的基礎設施實現的,要麼通過背後的實現類,要麼通過查詢執行引擎。當構建應用程序的時候,這兩種場景可能會覆蓋你所麵臨的很大範圍的數據訪問操作。但是,有些場景需要手動實現代碼。現在,讓我們看一下如何做到這一點。
我們開始隻實現那些需要手動實現的功能並在實現類中遵循一些命名的約定,如示例2-16所示。
示例2-16 為Repository實現自定義功能
接口和實現類均不需要了解Spring Data的任何事情。它與使用Spring手動實現代碼非常類似。按照Spring Data來看,這個代碼片段最有意思的地方在於實現類的名字遵循了命名的約定,也就是在核心Repository接口(在我們的場景中就是CustomerRepository)的名字上加Impl後綴。同時需要注意,我們將接口和實現類都設為包內私有(package private),從而阻止從包外訪問它們。
最後一步是修改初始Repository接口的聲明,使其擴展剛剛引入的接口,如示例2-17所示。
示例2-17 在CustomerRepository中包含自定義功能
現在,我們已經將CustomerRepositoryCustom暴露的API引入到CustomerRepository之中了,這會使其成為Customer數據訪問API的中心點。客戶端代碼現在就可以調用CustomerRepository.myCustomMethod(...)了。但是,這個實現類會如何被發現並置於最終執行的代理之中的呢?實際上,Repository的啟動過程看起來是這樣的。
1.發現repository接口(如CustomerRepository)。
2.嚐試尋找一個Bean定義,這個Bean的名字為接口的小寫形式並添加Impl後綴(如customerRepositoryImpl)。如果能夠找到,就使用它。
3.如果沒有找到,我們會掃描尋找一個類,這個類的名字為核心Repository接口的名字並添加Impl後綴(例如,在這個例子中CustomerRepositoryImpl會被找到)。如果找到了這樣的類,那麼將其注冊為Spring Bean並使用它。
4.找到的自定義實現類將會裝配到被發現接口的代理配置之中並且在方法調用時會作為潛在的目標類。
這種機製可以很容易地為特定Repository實現自定義代碼。用於進行實現查找的後綴可以在XML命名空間中或啟用Repository的注解屬性中(查看各種存儲相關的章節來了解更多)進行個性化設置。
最後更新:2017-05-31 12:31:38