領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多Spring Data 釋出列車 Fowler 的 GA 版釋出標誌著 6 個月開發的終點。現在是時候讓您瞭解此次釋出的內容並簡要概述各項功能了。Fowler 釋出列車的主要主題是效能改進和增強的 Java 8 支援,這主要體現在 Spring Data JPA 和 MongoDB 模組中,但許多其他模組也得到了顯著改進。
升級到 Spring Data Fowler 版本系列最簡單的方法是使用 Spring Boot 並將 spring-data-releasetrain.version 屬性配置為 Fowler-RELEASE。如果您尚未開始使用 Spring Boot,請將 Spring Data BOM 新增到您的 Maven POM 的 <dependencyManagement /> 部分。
Java 8 的一個重要新特性是 Stream API,它允許 Java 開發人員定義一個操作管道,對物件流執行操作,但只有最終的操作才會實際觸發對 Stream 中元素的消費。
在資料訪問的上下文中,將查詢執行的結果作為 Stream 提供是一個非常有用的用例,因為它可以防止查詢方法的呼叫者在所有項都讀取完畢之前阻塞。更不用說這裡更高效的記憶體使用。
在 Fowler 版本中,我們引入了對 Java 8 Stream 作為儲存庫中查詢方法返回型別的支援。在 MongoDB 和 JPA 模組中,您現在可以這樣宣告查詢方法
interface CustomerRepository extends Repository<Customer, Long> {
Stream<Customer> findByLastname(String lastname);
}
呼叫此方法將執行支援儲存庫方法的查詢,並在第一個結果可用時立即返回。為了在 JPA 中實現這一點,我們使用永續性提供程式特定的 API,因為 JPA 本身只提供以 List 形式獲取查詢結果的方法。儲存庫客戶端現在可以在 try-with-resources 塊中使用方法呼叫的結果。這將確保為遍歷流而開啟的資源最終會被關閉。
try (Stream<Customer> customers = repository.findByLastname("Matthews")) {
customers.filter(…).map(…).collect(…);
}
為了輕鬆持久化領域物件中的 無時區 JSR-310 型別——JDK 8 中新引入的日期/時間 API,我們在 MongoDB 和 JPA 模組中為相關型別添加了轉換器。對於尚不能升級到 Java 8 的開發人員,我們為 ThreeTen Backport 專案 添加了類似的轉換器集,這樣即使您仍在使用 Java 7,也可以在程式碼中開始使用這些型別。未來切換到 Java 8 將是包名稱的簡單切換。
在 MongoDB 模組中,相應的 Converter 實現是自動可用的。對於 JPA,您只需向永續性提供程式註冊 Jsr310JpaConverters 或 ThreeTenBackPortJpaConverters。如果您使用 LocalContainerEntityManagerFactoryBean 在 Spring 中設定 JPA 環境,只需將 org.springframework.data.jpa.convert.threeten 或 ….threetenbp 新增到要掃描的包中。對於 Spring Boot,只需將上述類新增到 @EntityScan 宣告中即可
@EntityScan(
basePackageClasses = { Application.class, Jsr310JpaConverters.class }
)
@SpringBootApplication
class Application { … }
此設定將確保您的應用程式包和 Spring Data JPA 包(用於 JSR-310 轉換器)都將被掃描並傳遞給永續性提供程式。有關完整示例,請參閱我們的 Spring Data Examples 儲存庫。請注意,由於轉換器只是將 JSR-310 型別轉換為舊版 Date 例項,因此 只支援無時區 型別(例如 LocalDateTime 等)。
Spring Data Fowler 支援最新最強大的 MongoDB 3.0 伺服器版本。雖然該版本已經可以透過 MongoDB Java 驅動程式 2.13.0 版本使用,但我們也確保 Spring Data MongoDB 將與即將推出的 Java 驅動程式 3.0 版本無縫協作。因此,開發人員可以自由選擇他們要使用的版本,或者何時升級到新驅動程式。有關驅動程式和伺服器版本之間相容性的通用資訊,請務必查閱 MongoDB 文件。但請注意,後續開發將明確關注伺服器和驅動程式的 3.0 版本線。
通常,我們鼓勵每個人在 JavaConfig 中優先使用 MongoClient 而不是 Mongo,或者使用新引入的 XML 元素 <mongo:mongo-client /> 和 <mongo:client-options />。有關更多資訊,請參閱參考文件。
MongoDB 引入 GeoJSON 作為處理地理結構格式已經有一段時間了。這些資料結構在類似地球的球體上操作,因此不能與 2D 索引一起使用。話雖如此,使用起來非常簡單,因為我們提供了專門的型別來支援 GeoJSON。這些型別既可以在您的域型別中使用,也可以作為查詢引數使用。
@Document
class Store {
@Id String id;
/**
* The location is stored in GeoJSON format:
* { "type" : "Point", "coordinates" : [ x, y ] }
*/
GeoJsonPoint location;
}
interface StoreRepository extends CrudRepository<Store, String> {
List<Store> findByLocationWithin(Polygon polygon);
}
repo.findByLocationWithin(
new GeoJsonPolygon(
new Point(-73.992514, 40.758934),
new Point(-73.961138, 40.760348),
new Point(-73.991658, 40.730006),
new Point(-73.992514, 40.758934)));
這將在 MongoDB 中建立以下查詢並執行
{
"location": {
"$geoWithin": {
"$geometry": {
"type": "Polygon",
"coordinates": [[
[-73.992514,40.758934],
[-73.961138,40.760348],
[-73.991658,40.730006],
[-73.992514,40.758934]
]]
}
}
}
}
請注意,StoreRepository.findByLocationWithin(…) 仍然接受 Polygon。使用 GeoJsonPolygon 和 findByLocationWithin(…) 將建立使用 $geometry 運算子以及 GeoJSON 表示的查詢。有關使用和限制的更多詳細資訊,請參閱 MongoDB 手冊。
MongoDB 允許在伺服器上執行 JavaScript 函式,方法是直接傳送原始源指令碼或呼叫先前儲存的指令碼。我們透過新引入的 ScriptOperations 介面公開此功能,該介面可以從 MongoOperations 獲取。
ScriptOperations ops = mongoOperations.scriptOps();
ExecutableMongoScript script = new ExecutableMongoScript("function(x) { return x; }");
Object r1 = ops.execute(script, "Direct function execution.")
ops.register(new NamedMongoScript("echo", script));
Object r2 = ops.call("echo", "Call stored function.");
伺服器端指令碼支援將在後續版本中得到增強,我們將新增返回型別轉換、用於從儲存庫方法呼叫過程的註解以及對 $where 運算子的支援。
物件到儲存的對映子系統在效能改進方面進行了重大改革。我們對 Commons 和儲存模組進行了分析,並在各處引入了一些快取,與 Evans 版本系列相比,我們實際獲得了令人印象深刻的每秒操作次數的增長(儘管大部分改進也已移植到 Evans 的服務版本中)。

如您所見,我們的讀取訪問每秒運算元增加了一倍以上,寫入操作也接近此水平。
從資料儲存中讀取大量物件時,透過反射建立物件例項會花費大量時間。在 Fowler 釋出系列中,我們引入了一個新的預設 EntityInstantiator,它透過使用 ASM 在執行時為域物件建立工廠類來解決這一瓶頸。該工廠類直接呼叫域類的建構函式,這比透過反射這樣做要快得多。如果您對這些精巧的細節感興趣,這裡是為我們完成這項工作的類。
Redis HyperLogLog 命令提供了一種高效的解決方案,可以在不記住已遇到元素的情況下計算唯一事物。例如,這適用於按 IP 地址計算唯一頁面訪問量。
HyperLogLogOperations hll = redisTemplate.opsForHyperLogLog();
hll.add(today(), "8.8.8.8", "8.8.4.4");
hll.size(today()); // Unique page visits today = 2
hll.add(today(), "198.153.192.40", "8.8.8.8");
hll.size(today()); // Unique page visits today = 3
hll.size(today(), yesterday()); // Unique page visits today and yesterday
到目前為止,GemFire 模組最顯著的變化是全面支援 GemFire 8。GemFire 8 自 7.0.2 以來引入了多項新變化,包括新的基於叢集的配置服務。
啟用該服務後,開發人員可以在 Gfsh 中記錄他們的操作和類似模式的更改,例如新增區域、建立索引、配置磁碟儲存等。當開發人員在叢集中啟動新的 GemFire 對等節點時,該成員將自動從新的基於叢集的配置服務(託管在定位器中)獲取其配置。
雖然 Spring Data GemFire 的基於 XML 名稱空間的配置仍然是流行的選擇,尤其是在高度迭代、短反饋週期的開發過程中,Spring Data GemFire 增加了對新基於叢集的配置的支援,這與 Spring Data Gemfire 對 GemFire 的原生 `cache.xml 格式的支援行為類似。
要在 Spring 配置的 GemFire 節點中啟用基於叢集的配置,開發人員只需在 <gfe:cache /> 元素上設定 use-cluster-configuration 屬性,如下所示
<gfe:cache id="gemfireCache" use-cluster-configuration="true" … />
Spring Data GemFire 將首先請求並應用叢集範圍的配置,然後應用 XML 名稱空間特定的配置。您可以將 XML 配置元資料視為對叢集配置服務傳送的叢集配置的增強。
有關 GemFire 新叢集配置服務的更多資訊,請參閱 GemFire 使用者指南 和 SGF-226 以獲取更多詳細資訊。
Spring Data REST 在 Fowler 版本中也進行了廣泛的改進。最顯著的改進之一是檢查和使用更多實體元資料來填充響應頭。例如,支援透過 @Version 註解進行樂觀鎖定的儲存現在將獲取用作 ETag 頭的實體版本,以便客戶端可以利用它們觸發條件 GET 請求。
與此密切相關的是,使用 Spring Data 審計支援的實體將自動將其上次修改日期傳播到專案資源的響應的 LastModified 頭中
class Customer {
@Version Long version;
@LastModifiedDate LocalDate lastModifiedDate;
}
curl -v http://…/customers/1
Etag: 1
Last-Modified: Tue, 24 Mar 2015 12:34:56 GMT
Spring Data REST 的 Fowler 版本也提供了經過改進的 JSON Schema 支援。預設情況下,模式由 ALPS 文件中公開的表示描述符指向,該文件用於域型別。在 Starbucks 示例中,您可以看到連結的渲染方式如下
curl http://…/alps/stores
{
"version": "1.0",
"descriptors": [ {
"id": "store-representation",
"href": "https://:8080/stores/schema",
"descriptors": [ … ]
}],
…
}
點選連結將顯示商店的 JSON Schema 文件
{
"title": "example.stores.Store",
"properties": {
"address": {
"$ref": "#/descriptors/address"
},
"name": {
"type": "string"
}
},
"descriptors": {
"address": {
"type": "object",
"properties": {
"zip": {
"type": "string"
},
"city": {
"type": "string"
},
"street": {
"type": "string"
},
"location": {
"$ref": "#/descriptors/point"
}
}
},
"point": {
"type": "object",
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
}
}
}
},
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema#"
}
請注意我們如何從領域型別及其 Jackson 對映中推匯出模式的基本特徵。所需屬性可以透過使用 @JsonProperty(required = true) 來確定,日期/時間型別被正確發現並宣告。您可以在 RepositoryRestConfiguration.metadataConfiguration() 上註冊自定義 JSON Schema 格式或模式。
@Configuration
static class SampleConfiguration extends RepositoryRestMvcConfiguration {
@Override
protected void configureRepositoryRestConfiguration(
RepositoryRestConfiguration config) {
config.metadataConfiguration().
registerJsonSchemaFormat(JsonSchemaFormat.EMAIL, EmailAddress.class);
}
}
假設 EmailAddress 是一個您已調整 Jackson 以將其渲染為純 String 的值物件,則此配置將導致所有 EmailAddress 型別的屬性在 JSON 模式文件中以 format 設定為 email 出現。
Fowler 版本增加了對即時獲取的支援,允許從索引中讀取未提交的更改。SolrTemplate 上提供了 getById 方法。另外值得注意的是添加了 @Score,它受到了 Spring Data MongoDB 可用的 @TextScore 的啟發。該註解允許檢索文件評分,並將隱式新增所需引數,因此在檢索文件查詢匹配評分時不再需要顯式新增 @Query(fields={"*", "score"}。
Spring Data REST 在 Evans 版本系列中釋出了一個名為投影的功能。在 Fowler 版本中,我們將支援該功能的基礎設施移至 Spring Data Commons,並對其進行了一些調整,以便其他專案可以在沒有額外依賴的情況下使用它。該功能的核心是 ProjectionFactory,它允許您為由其他物件(例如 Map)支援的介面建立物件例項。
interface Customer {
String getFirstname();
String getLastname();
@Value("#{target.firstname + ' ' + target.lastname}")
String getFullName();
}
現在可以使用 ProjectionFactory 將此介面轉換為物件。
Map<String, Object> map = new HashMap<>();
map.put("firstname", "Dave");
map.put("lastname", "Matthews");
ProjectionFactory factory = new SpelAwareProjectionFactory();
Customer customer = factory.createProjection(Customer.class, map)
assertThat(customer.getFirstname(), is("Dave"));
assertThat(customer.getLastname(), is("Matthews"));
assertThat(customer.getFullName(), is("Dave Matthews"));
如您所見,我們選擇了一個 Map 來支援建立的投影例項。在底層,建立了一個 JDK 代理,它配備了方法攔截器,在 Map 支援代理的情況下,它將對訪問器的呼叫委託給 Map 中的屬性查詢。使用 @Value 註解的方法將對其註解的 SpEL 表示式進行求值。如果您在 SpelAwareProjectionFactory 上配置 BeanFactory,您甚至可以在這些表示式中引用 Spring bean,從而觸發更復雜的計算。
如果後臺查詢未返回可分配給宣告的返回型別的值,則會使用標準 ConversionService 進行簡單轉換,然後進行遞迴投影步驟。
有關如何在 Spring MVC 控制器中使用投影的示例,請參閱 StackOverflow 上的此答案。
投影機制現在可以被 Spring MVC 控制器實現使用,以僅使用介面建立表單支援物件。在您的 Spring 配置中使用 @EnableSpringDataWebSupport(在 Boot 中自動啟用)將解析 ProxyingHandlerMethodArgumentResolver,它將自動為介面建立代理例項並將相應的請求引數繫結到它。
interface Form {
@NotBlank String getName();
@NotBlank String getText();
}
@Controller
@RequestMapping(value = "/guestbook")
class GuestbookController {
@RequestMapping(method = RequestMethod.GET)
String guestbook(Form form, Model model) { … }
@RequestMapping(method = RequestMethod.POST)
String guestbook(@Valid Form form, Errors errors, Model model) { … }
}
請看介面如何在接受 GET 請求的方法中使用,以便為即將渲染的檢視提供一個空的表單支援物件。接收 POST 請求的方法使用 Form 來指示它希望將表單資料繫結到代理例項並應用驗證。
儘管這篇文章很長,但我們只是簡單介紹了 Spring Data Fowler 版本的所有新功能。您可能需要瀏覽 發行版系列 wiki 以尋找更多精彩內容,並依次遍歷指向票據和相關提交的連結,因為它們包含通常很好地演示各個功能的測試用例。
此外,前面提到的 Spring Data 示例倉庫 也包含大量可供您嘗試和探索的內容。