© 2010-2019 原始作者。

您可以為自己使用或分發本檔案,但前提是您不得為此類副本收取任何費用,並且每個副本(無論是印刷版還是電子版)都包含此版權宣告。

前言

Pivotal GemFire 的 Spring Data 專注於將 Spring 框架強大的非侵入式程式設計模型和概念與 Pivotal GemFire 整合,以簡化使用 Pivotal GemFire 作為資料管理解決方案時 Java 應用程式的配置和開發。

本文件假定您已經對核心 Spring 框架和 Pivotal GemFire 概念有基本瞭解和一些熟悉。

儘管已盡一切努力確保本文件全面、完整且無錯誤,但某些主題超出了本文件的範圍,可能需要更多解釋(例如,使用 HA 的分割槽進行資料分發管理,同時仍保持一致性)。此外,可能存在一些印刷錯誤。如果您發現錯誤,甚至更嚴重的錯誤,請透過在 JIRA 中提出相應問題,提請 Spring Data 團隊注意這些問題。

1. 簡介

Pivotal GemFire 的 Spring Data 參考指南解釋瞭如何使用 Spring 框架配置和開發 Pivotal GemFire 應用程式。它介紹了基本概念並提供了大量示例,幫助您快速入門。

2. 要求

Pivotal GemFire 的 Spring Data 需要 Java 8.0、Spring Framework 5 和 Pivotal GemFire 9.8.2。

3. 新特性

從 1.2.0.RELEASE 開始,這個專案(以前稱為 Spring GemFire)已更名為 Pivotal GemFire 的 Spring Data,以反映它現在是 Spring Data 專案的一個模組,並且基於 Pivotal GemFire 構建。

3.1. 1.2 版本的新特性

  • 透過 SDG gfe XML 名稱空間完全支援 Pivotal GemFire 配置。現在可以完全配置 Pivotal GemFire 元件,而無需本地 cache.xml 檔案。

  • 對 Pivotal GemFire 6.6.x 的 WAN Gateway 支援。請參閱 配置 WAN 閘道器

  • 使用專用 SDG XML 名稱空間 gfe-data 支援 Spring Data 儲存庫。請參閱 Pivotal GemFire 的 Spring Data 儲存庫

  • gfe-data XML 名稱空間支援註冊 Pivotal GemFire 函式。請參閱 配置函式服務

  • 已將頂級 <disk-store> 元素新增到 SDG gfe XML 名稱空間,以允許區域以及支援持久備份或溢位的其他 Pivotal GemFire 元件之間共享持久儲存。請參閱 [bootstrap-diskstore]

    <*-region> 元素不再允許巢狀的 <disk-store> 元素。
  • Pivotal GemFire 子區域透過巢狀的 <*-region> 元素支援。

  • 已新增 <local-region> 元素來配置本地區域。

  • 支援 Pivotal GemFire 7.0 中重新設計的 WAN Gateway。

3.2. 1.3 版本的新特性

  • 升級到 Spring Framework 3.2.8。

  • 升級到 Spring Data Commons 1.7.1。

  • 對 Pivotal GemFire 函式的註解支援。現在可以透過使用註解來宣告和註冊編寫為 POJO 的函式。此外,函式執行被定義為帶註解的介面,類似於 Spring Data 儲存庫的工作方式。請參閱 函式執行的註解支援

  • 已將 <datasource> 元素新增到 SDG XML 名稱空間,以簡化與 Pivotal GemFire 資料網格建立基本客戶端連線

  • 已將 <json-region-autoproxy> 元素新增到 SDG gfe-data XML 名稱空間,以支援 Pivotal GemFire 7.0 中引入的 JSON 功能,從而使 Spring AOP 能夠在區域資料訪問操作上自動執行必要的轉換。

  • 升級到 Pivotal GemFire 7.0.1 並添加了對新 AsyncEventQueue 屬性的 XML 名稱空間支援。

  • 添加了對設定區域訂閱興趣策略的支援。

  • 支援函式執行的 void 返回。有關完整詳細資訊,請參閱 函式執行的註解支援

  • 支援持久化本地區域。請參閱 本地區域

  • 支援 Pivotal GemFire 客戶端快取上的條目生存時間 (TTL) 和條目空閒時間 (TTI)。請參閱 配置 Pivotal GemFire ClientCache

  • 透過使用單個 Pivotal GemFire 叢集,支援多個基於 Pivotal GemFire 的 Spring Data Web 應用程式在 tc Server 內部併發執行。

  • 透過使用 SDG gfe XML 名稱空間,支援所有快取區域定義上的 concurrency-checks-enabled。請參閱 [bootstrap:region:common:attributes]

  • 支援客戶端本地區域上的 CacheLoadersCacheWriters

  • 支援在 Pivotal GemFire 快取子區域上註冊 CacheListenersAsyncEventQueuesGatewaySenders

  • 支援區域中的 PDX 持久金鑰。

  • 在 Spring 上下文中指定 colocated-with 屬性進行協同定位時,支援正確的 Partition Region bean 建立。

  • 使用 SDG gfe XML 名稱空間中適當的巢狀 <*-region> 元素語法,完全支援快取子區域。

3.3. 1.4 版本的新特性

  • 升級到 Pivotal GemFire 7.0.2。

  • 升級到 Spring Framework 3.2.13.RELEASE。

  • 升級到 Spring Data Commons 1.8.6.RELEASE。

  • 將 Pivotal GemFire 的 Spring Data 與 Spring Boot 整合,其中包括 spring-boot-starter-data-gemfire POM 和一個 Spring Boot 示例應用程式,該應用程式演示了使用 SDG 配置並使用 Spring Boot 引導的 Pivotal GemFire 快取事務。

  • 添加了對從 Gfsh 啟動時在 Pivotal GemFire 伺服器中引導 Spring ApplicationContext 的支援。請參閱 在 Pivotal GemFire 中引導 Spring ApplicationContext

  • 添加了對將應用程式域物件和實體持久化到多個 Pivotal GemFire 快取區域的支援。請參閱 實體對映

  • 添加了對將應用程式域物件和實體持久化到 Pivotal GemFire 快取子區域的支援,避免了當子區域可唯一識別但名稱相同時的衝突。請參閱 實體對映

  • 對所有 Pivotal GemFire 快取區域型別的資料策略和區域快捷方式添加了嚴格的 XSD 型別規則。

  • 將 SDG <*-region> 元素的預設行為從查詢更改為始終建立一個新區域,並提供了一個選項,可以使用 ignore-if-exists 屬性恢復舊行為。請參閱 常用區域屬性[bootstrap:region:common:regions-subregions-lookups-caution]

  • Pivotal GemFire 的 Spring Data 現在可以完全在 JDK 7 和 JDK 8 上構建和執行。

3.4. 1.5 版本的新特性

  • 與 Pivotal GemFire 7.0.2 保持相容性。

  • 升級到 Spring Framework 4.0.9.RELEASE。

  • 升級到 Spring Data Commons 1.9.4.RELEASE。

  • 將參考指南轉換為 Asciidoc。

  • 重新支援在 OSGi 容器中部署 Pivotal GemFire 的 Spring Data。

  • 刪除了 Pivotal GemFire XML 名稱空間區域型別元素中指定的所有預設值,轉而依賴 Pivotal GemFire 的預設值。

  • 增加了自動建立 DiskStore 目錄位置的便利性。

  • SDG 註解的函式實現現在可以從 Gfsh 執行。

  • 啟用了手動啟動 Pivotal GemFire GatewayReceivers

  • 添加了對自動區域查詢的支援。請參閱 [bootstrap:region:auto-lookup]

  • 添加了對區域模板的支援。請參閱 [bootstrap:region:common:region-templates]

3.5. 1.6 版本的新特性

  • 升級到 Pivotal GemFire 8.0.0。

  • 與 Spring Framework 4.0.9.RELEASE 保持相容性。

  • 升級到 Spring Data Commons 1.10.2.RELEASE。

  • 添加了對 Pivotal GemFire 8 新的基於叢集的配置服務的支援。

  • 啟用了在 Spring 配置的 Pivotal GemFire 伺服器中採用“自動重新連線”功能。

  • 允許建立併發和並行的 AsyncEventQueuesGatewaySenders

  • 添加了對 Pivotal GemFire 8 區域資料壓縮的支援。

  • 添加了用於設定 DiskStore 使用率臨界和警告百分比的屬性。

  • 支援向 GatewaySenders 新增 EventSubstitutionFilters 的功能。

3.6. 1.7 版本的新特性

  • 升級到 Pivotal GemFire 8.1.0。

  • 升級到 Spring Framework 4.1.9.RELEASE。

  • 升級到 Spring Data Commons 1.11.6.RELEASE。

  • 添加了對 Apache Geode 的早期訪問支援。

  • 添加了對在 Spring XML、cache.xml 甚至 Pivotal GemFire 的叢集配置服務中配置的現有區域上新增 Spring 定義的 CacheListenersCacheLoadersCacheWriters 的支援。

  • 添加了對 SpringContextBootstrappingInitializer 的 Spring JavaConfig 支援。

  • 添加了對 SpringContextBootstrappingInitializer 中自定義 ClassLoaders 的支援,以載入 Spring 定義的 bean 類。

  • 添加了對 LazyWiringDeclarableSupport 重新初始化和 WiringDeclarableSupport 的完全替換的支援。

  • <gfe:pool> 元素中添加了 locatorsservers 屬性,允許使用 Spring 的屬性佔位符配置可變定位器和伺服器端點列表。

  • 啟用了在非 Spring 配置的 Pivotal GemFire 伺服器上使用 <gfe-data:datasource> 元素。

  • 添加了多索引定義和建立支援。

  • 基於註解的資料過期

  • [gemfire-repositories:oql-extensions]

  • 添加了對快取和區域資料快照的支援。請參閱 配置快照服務

3.7. 1.8 版本的新特性

  • 升級到 Pivotal GemFire 8.2.0。

  • 升級到 Spring Framework 4.2.9.RELEASE。

  • 升級到 Spring Data Commons 1.12.11.RELEASE。

  • 添加了 Maven POM 以使用 Maven 構建 SDG。

  • 添加了對 CDI 的支援。

  • 啟用了在沒有 Pool 的情況下配置 ClientCache

  • <gfe:cache><gfe:client-cache> 元素的 use-bean-factory-locator 屬性預設為 false

  • <gfe:client-cache> 中添加了 durable-client-iddurable-client-timeout 屬性。

  • 使 GemfirePersistentProperty 現在能正確處理其他非實體、類似標量的型別(例如 BigDecimalBigInteger)。

  • 防止 SDG 定義的 Pools 在使用這些 PoolsRegions 之前被銷燬。

  • 處理了定義為儲存庫查詢方法的 Pivotal GemFire OQL 查詢不區分大小寫的情況。

  • 將 SDG Spring 快取抽象支援中的 GemFireCache.evict(key) 更改為呼叫 Region.remove(key)

  • 修復了在客戶端 Region 上進行儲存庫查詢時出現的 RegionNotFoundException,該 Region 與為 Pivotal GemFire 伺服器組配置的特定 Pool 相關聯。

  • GatewaySenders/Receivers 不再與 Spring 容器繫結。

3.8. 1.9 版本的新特性

  • 升級到 Pivotal GemFire 8.2.11。

  • 升級到 Spring Framework 4.3.18.RELEASE。

  • 升級到 Spring Data Commons 1.13.13.RELEASE。

  • 引入了一個全新的、受 Spring Boot 啟發的基於註解的配置模型。

  • GemfireTransactionManager 中添加了對暫停和恢復的支援。

  • 在儲存庫中添加了支援,當不存在 @Id 註解時,使用 bean id 屬性作為區域鍵。

  • 當使用 @EnablePdx 時,將 MappingPdxSerializer 用作預設的 Pivotal GemFire 序列化策略。

  • 啟用了 GemfireCacheManager 顯式列出要在 Spring 快取抽象中使用的區域名稱。

  • 配置了 Pivotal GemFire 快取、CacheServers、Locators、Pools、Regions、Indexes、DiskStores、Expiration、Eviction、Statistics、Mcast、HttpService、Auth、SSL、Logging、System Properties。

  • 在類路徑上添加了多個 Spring Data 模組的儲存庫支援。

3.9. 2.0 版本的新特性

  • 升級到 Pivotal GemFire 9.1.1。

  • 升級到 Spring Data Commons 2.0.8.RELEASE。

  • 升級到 Spring Framework 5.0.7.RELEASE。

  • 透過按關注點打包不同的類和元件來重組 SDG 程式碼庫。

  • 為 Java 8 型別添加了廣泛的支援,尤其是在 SD 儲存庫抽象中。

  • 更改了儲存庫介面和抽象,例如,ID 不再需要是 java.io.Serializable

  • @EnableEntityDefinedRegions 註解的 ignoreIfExists 屬性預設設定為 true

  • @Indexed 註解的 override 屬性預設設定為 false

  • @EnableIndexes 重新命名為 @EnableIndexing

  • 引入了 InterestsBuilder 類,以便在使用 JavaConfig 時輕鬆方便地表達客戶端和伺服器之間對鍵和值的興趣。

  • 在註解配置模型中添加了對堆外記憶體、Redis 介面卡和 Pivotal GemFire 新安全框架的支援。

3.10. 2.1 版本的新特性

  • 升級到 Pivotal GemFire 9.8.2。

  • 升級到 Spring Framework 5.1.0.RELEASE。

  • 升級到 Spring Data Commons 2.1.0.RELEASE。

  • 添加了對並行快取/區域快照的支援,以及在載入快照時呼叫回撥函式。

  • 添加了對註冊 QueryPostProcessors 的支援,以自定義從儲存庫查詢方法生成的 OQL。

  • 添加了對 o.s.d.g.mapping.MappingPdxSerializer 中包含/排除 TypeFilters 的支援。

  • 更新了文件。

參考指南

4. 文件結構

以下章節解釋了 Pivotal GemFire 的 Spring Data 提供的核心功能

  • 使用 Spring 容器引導 Pivotal GemFire 描述了為配置、初始化和訪問 Pivotal GemFire 快取、區域和相關分散式系統元件提供的配置支援。

  • 使用 Pivotal GemFire API 解釋了 Pivotal GemFire API 與 Spring 中可用的各種資料訪問功能之間的整合,例如基於模板的資料訪問、異常轉換、事務管理和快取。

  • 使用 Pivotal GemFire 序列化 描述了 Pivotal GemFire 對託管物件的序列化和反序列化的增強功能。

  • POJO 對映 描述了使用 Spring Data 儲存在 Pivotal GemFire 中的 POJO 的持久化對映。

  • Pivotal GemFire 的 Spring Data 儲存庫 描述瞭如何建立和使用 Spring Data 儲存庫,透過基本的 CRUD 和簡單的查詢操作訪問儲存在 Pivotal GemFire 中的資料。

  • 函式執行的註解支援 描述瞭如何使用註解建立和使用 Pivotal GemFire 函式,以在資料所在的位置執行分散式計算。

  • 連續查詢 (CQ) 描述瞭如何使用 Pivotal GemFire 的連續查詢 (CQ) 功能,根據 Pivotal GemFire 的 OQL(物件查詢語言)定義和註冊的興趣來處理事件流。

  • 在 Pivotal GemFire 中引導 Spring ApplicationContext 描述瞭如何使用 Gfsh 配置和引導在 Pivotal GemFire 伺服器中執行的 Spring ApplicationContext

  • 示例應用程式 描述了分發中提供的示例,以說明 Pivotal GemFire 的 Spring Data 中可用的各種功能。

5. 使用 Spring 容器引導 Pivotal GemFire

Pivotal GemFire 的 Spring Data 使用 Spring IoC 容器提供 Pivotal GemFire 記憶體資料網格 (IMDG) 的完整配置和初始化。該框架包含幾個類,以幫助簡化 Pivotal GemFire 元件的配置,包括:快取、區域、索引、磁碟儲存、函式、WAN 閘道器、持久化備份以及其他幾個分散式系統元件,以最少的努力支援各種應用程式用例。

本節假定您對 Pivotal GemFire 有基本瞭解。有關更多資訊,請參閱 Pivotal GemFire 產品文件

5.1. 使用 Spring 優於 Pivotal GemFire cache.xml 的優點

Pivotal GemFire 的 Spring Data 的 XML 名稱空間支援 Pivotal GemFire 記憶體資料網格 (IMDG) 的完整配置。XML 名稱空間是 Spring 上下文中配置 Pivotal GemFire 的兩種方法之一,以便在 Spring 容器中正確管理 Pivotal GemFire 的生命週期。在 Spring 上下文中配置 Pivotal GemFire 的另一種方法是使用 基於註解的配置

雖然出於遺留原因仍支援 Pivotal GemFire 的原生 cache.xml,但鼓勵使用 XML 配置的 Pivotal GemFire 應用程式開發人員在 Spring XML 中完成所有操作,以利用 Spring 提供的許多出色功能,例如模組化 XML 配置、屬性佔位符和覆蓋、SpEL(Spring 表示式語言)和環境配置檔案。在 XML 名稱空間背後,Pivotal GemFire 的 Spring Data 大量使用 Spring 的 FactoryBean 模式來簡化 Pivotal GemFire 元件的建立、配置和初始化。

Pivotal GemFire 提供了幾個回撥介面,例如 CacheListenerCacheLoaderCacheWriter,允許開發人員新增自定義事件處理程式。使用 Spring 的 IoC 容器,您可以將這些回撥配置為正常的 Spring bean 並將其注入到 Pivotal GemFire 元件中。與原生 cache.xml 相比,這是一個顯著的改進,原生 cache.xml 提供了相對有限的配置選項,並要求回撥實現 Pivotal GemFire 的 Declarable 介面(請參閱 連線 Declarable 元件,瞭解如何在 Spring 容器中使用 Declarables)。

此外,IDE(例如 Spring Tool Suite (STS))為 Spring XML 名稱空間提供了出色的支援,包括程式碼完成、彈出註解和即時驗證。

5.2. 使用核心名稱空間

為了簡化配置,Pivotal GemFire 的 Spring Data 為配置核心 Pivotal GemFire 元件提供了專用的 XML 名稱空間。可以透過使用 Spring 的標準 <bean> 定義直接配置 bean。但是,所有 bean 屬性都透過 XML 名稱空間公開,因此使用原始 bean 定義幾乎沒有好處。

有關 Spring 中基於 XML Schema 的配置的更多資訊,請參閱 Spring Framework 參考文件中的附錄
Spring Data Repository 支援使用單獨的 XML 名稱空間。有關如何配置 Pivotal GemFire 的 Spring Data Repository 的更多資訊,請參閱 Pivotal GemFire 的 Spring Data Repository

要使用 Pivotal GemFire 的 Spring Data XML 名稱空間,請在您的 Spring XML 配置元資料中宣告它,如以下示例所示

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:gfe="https://www.springframework.org/schema/gemfire" (1)(2)
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    https://www.springframework.org/schema/gemfire https://www.springframework.org/schema/gemfire/spring-gemfire.xsd (3)
">

  <bean id ... >

  <gfe:cache ...> (4)

</beans>
1 Pivotal GemFire 的 Spring Data XML 名稱空間字首。任何名稱都可以,但在整個參考文件中都使用 gfe
2 XML 名稱空間字首對映到 URI。
3 XML 名稱空間 URI 位置。請注意,即使該位置指向一個外部地址(它確實存在且有效),Spring 也會在本地解析模式,因為它包含在 Pivotal GemFire 的 Spring Data 庫中。
4 使用帶 gfe 字首的 XML 名稱空間宣告示例。

您可以將預設名稱空間從 beans 更改為 gfe。這對於主要由 Pivotal GemFire 元件組成的 XML 配置非常有用,因為它避免了宣告字首。為此,請交換前面所示的名稱空間字首宣告,如以下示例所示

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/gemfire" (1)
       xmlns:beans="http://www.springframework.org/schema/beans" (2)
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    https://www.springframework.org/schema/gemfire https://www.springframework.org/schema/gemfire/spring-gemfire.xsd
">

  <beans:bean id ... > (3)

  <cache ...> (4)

</beans>
1 此 XML 文件的預設名稱空間宣告指向 Pivotal GemFire 的 Spring Data XML 名稱空間。
2 Spring 原始 bean 定義的 beans 名稱空間字首宣告。
3 使用 beans 名稱空間的 bean 宣告。注意字首。
4 使用 gfe 名稱空間的 bean 宣告。注意由於 gfe 是預設名稱空間而沒有字首。

5.3. 使用資料訪問名稱空間

除了核心 XML 名稱空間 (gfe) 之外,Pivotal GemFire 的 Spring Data 還提供了一個數據訪問 XML 名稱空間 (gfe-data),主要旨在簡化 Pivotal GemFire 客戶端應用程式的開發。此名稱空間目前包含對 Pivotal GemFire 儲存庫和函式執行的支援,以及一個 <datasource> 標籤,它提供了一種連線到 Pivotal GemFire 叢集的便捷方式。

5.3.1. 連線到 Pivotal GemFire 的簡單方法

對於許多應用程式來說,使用預設值與 Pivotal GemFire 資料網格的基本連線就足夠了。Pivotal GemFire 的 Spring Data 的 <datasource> 標籤提供了一種簡單的資料訪問方式。資料來源會建立一個 ClientCache 和連線 Pool。此外,它會查詢叢集伺服器以獲取所有現有根區域,併為每個區域建立一個(空)客戶端區域代理。

<gfe-data:datasource>
  <locator host="remotehost" port="1234"/>
</gfe-data:datasource>

<datasource> 標籤在語法上與 <gfe:pool> 相似。它可以配置一個或多個巢狀的 locatorserver 元素來連線到現有資料網格。此外,所有可用於配置 Pool 的屬性都受支援。此配置會自動為連線到 Locator 的叢集成員上定義的每個區域建立客戶端區域 bean,因此它們可以被 Spring Data 對映註解 (GemfireTemplate) 無縫引用並自動注入到應用程式類中。

當然,您可以顯式配置客戶端區域。例如,如果您想在本地記憶體中快取資料,如以下示例所示

<gfe-data:datasource>
  <locator host="remotehost" port="1234"/>
</gfe-data:datasource>

<gfe:client-region id="Example" shortcut="CACHING_PROXY"/>

5.4. 配置快取

要使用 Pivotal GemFire,您需要建立新快取或連線到現有快取。在當前版本的 Pivotal GemFire 中,每個 VM(更嚴格地說,每個 ClassLoader)只能開啟一個快取。在大多數情況下,快取應該只建立一次。

本節描述對等 Cache 成員的建立和配置,適用於對等 (P2P) 拓撲和快取伺服器。Cache 成員也可以用於獨立應用程式和整合測試。但是,在典型的生產系統中,大多數應用程式程序充當快取客戶端,而是建立 ClientCache 例項。這在配置 Pivotal GemFire ClientCache客戶端區域部分中進行了描述。

可以使用以下簡單宣告建立具有預設配置的對等 Cache

<gfe:cache/>

在 Spring 容器初始化期間,任何包含此快取定義的 ApplicationContext 都會註冊一個 CacheFactoryBean,該工廠 bean 建立一個名為 gemfireCache 的 Spring bean,該 bean 引用一個 Pivotal GemFire Cache 例項。此 bean 引用現有 Cache,或者,如果不存在,則引用新建立的 Cache。由於未指定附加屬性,因此新建立的 Cache 應用預設快取配置。

所有依賴於 Cache 的 Pivotal GemFire 的 Spring Data 元件都遵循此命名約定,因此您無需顯式宣告 Cache 依賴項。如果您願意,可以透過使用各種 SDG XML 名稱空間元素提供的 cache-ref 屬性使依賴項顯式化,如下所示,您可以使用 id 屬性覆蓋快取的 bean 名稱

<gfe:cache id="myCache"/>

Pivotal GemFire Cache 可以使用 Spring 完全配置。但是,Pivotal GemFire 的原生 XML 配置檔案 cache.xml 也受支援。對於需要原生配置 Pivotal GemFire 快取的情況,您可以透過使用 cache-xml-location 屬性提供對 Pivotal GemFire XML 配置檔案的引用,如下所示

<gfe:cache id="cacheConfiguredWithNativeCacheXml" cache-xml-location="classpath:cache.xml"/>

在此示例中,如果需要建立快取,它將使用位於類路徑根目錄下的名為 cache.xml 的檔案進行配置。

該配置利用 Spring 的 Resource 抽象來定位檔案。Resource 抽象允許使用各種搜尋模式,具體取決於執行時環境或資源位置中指定的(如果有)字首。

除了引用外部 XML 配置檔案之外,您還可以指定使用 Spring Properties 支援功能的任何 Pivotal GemFire System 屬性

例如,您可以使用 util 名稱空間中定義的 properties 元素直接定義 Properties 或從屬性檔案中載入屬性,如下所示

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:gfe="https://www.springframework.org/schema/gemfire"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    https://www.springframework.org/schema/gemfire https://www.springframework.org/schema/gemfire/spring-gemfire.xsd
    http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd
">

  <util:properties id="gemfireProperties" location="file:/path/to/gemfire.properties"/>

  <gfe:cache properties-ref="gemfireProperties"/>

</beans>

建議使用屬性檔案將特定於環境的設定外部化到應用程式配置之外。

快取設定僅在需要建立新快取時才適用。如果 VM 中已存在開啟的快取,則這些設定將被忽略。

5.4.1. 高階快取配置

對於高階快取配置,cache 元素提供了許多配置選項,這些選項作為屬性或子元素公開,如以下列表所示

(1)
<gfe:cache
    cache-xml-location=".."
    properties-ref=".."
    close="false"
    copy-on-read="true"
    critical-heap-percentage="90"
    eviction-heap-percentage="70"
    enable-auto-reconnect="false" (2)
    lock-lease="120"
    lock-timeout="60"
    message-sync-interval="1"
    pdx-serializer-ref="myPdxSerializer"
    pdx-persistent="true"
    pdx-disk-store="diskStore"
    pdx-read-serialized="false"
    pdx-ignore-unread-fields="true"
    search-timeout="300"
    use-bean-factory-locator="true" (3)
    use-cluster-configuration="false" (4)
>

  <gfe:transaction-listener ref="myTransactionListener"/> (5)

  <gfe:transaction-writer> (6)
    <bean class="org.example.app.gemfire.transaction.TransactionWriter"/>
  </gfe:transaction-writer>

  <gfe:gateway-conflict-resolver ref="myGatewayConflictResolver"/> (7)

  <gfe:dynamic-region-factory/> (8)

  <gfe:jndi-binding jndi-name="myDataSource" type="ManagedDataSource"/> (9)

</gfe:cache>
1 屬性支援各種快取選項。有關此示例中所示的任何內容的更多資訊,請參閱 Pivotal GemFire 產品文件close 屬性確定在關閉 Spring 應用程式上下文時是否應關閉快取。預設值為 true。但是,對於多個應用程式上下文使用快取的用例(在 Web 應用程式中很常見),請將此值設定為 false
2 enable-auto-reconnect 屬性設定為 true(預設為 false)允許斷開連線的 Pivotal GemFire 成員自動重新連線並重新加入 Pivotal GemFire 叢集。有關更多詳細資訊,請參閱 Pivotal GemFire 產品文件
3 use-bean-factory-locator 屬性設定為 true(預設為 false)僅在同時使用 Spring (XML) 配置元資料和 Pivotal GemFire cache.xml 配置 Pivotal GemFire 快取節點(無論是客戶端還是對等節點)時適用。此選項允許 cache.xml 中表達的 Pivotal GemFire 元件(例如 CacheLoader)與 Spring 應用程式上下文中定義的 bean(例如 DataSource)自動連線。此選項通常與 cache-xml-location 結合使用。
4 use-cluster-configuration 屬性設定為 true(預設為 false)使 Pivotal GemFire 成員能夠從 Locator 檢索通用、共享的基於叢集的配置。有關更多詳細資訊,請參閱 Pivotal GemFire 產品文件
5 使用 bean 引用的 TransactionListener 回撥宣告示例。引用的 bean 必須實現 TransactionListener。可以實現 TransactionListener 來處理事務相關事件(例如 afterCommit 和 afterRollback)。
6 使用內部 bean 宣告的 TransactionWriter 回撥宣告示例。該 bean 必須實現 TransactionWriterTransactionWriter 是一個可以否決事務的回撥。
7 使用 bean 引用的 GatewayConflictResolver 回撥宣告示例。引用的 bean 必須實現 https://gemfire-98-javadocs.docs.pivotal.io//org/apache/geode/cache/util/GatewayConflictResolver.html [GatewayConflictResolver]。GatewayConflictResolver 是一個 Cache 級別的外掛,用於決定如何處理源自其他系統並透過 WAN Gateway 到達的事件。
8 啟用 Pivotal GemFire 的 DynamicRegionFactory,它提供分散式區域建立服務。
9 宣告一個 JNDI 繫結,將外部 DataSource 加入到 Pivotal GemFire 事務中。
啟用 PDX 序列化

前面的示例包含許多與 Pivotal GemFire 增強型序列化框架 PDX 相關的屬性。雖然對 PDX 的完整討論超出了本參考指南的範圍,但需要注意的是,PDX 是透過註冊一個 PdxSerializer 來啟用的,該序列化器透過設定 pdx-serializer 屬性來指定。

Pivotal GemFire 提供了一個使用 Java 反射的實現類 (org.apache.geode.pdx.ReflectionBasedAutoSerializer)。然而,開發人員通常會提供自己的實現。屬性的值只是對實現 PdxSerializer 介面的 Spring bean 的引用。

有關序列化支援的更多資訊,請參閱 使用 Pivotal GemFire 序列化

啟用自動重新連線

設定 <gfe:cache enable-auto-reconnect="[true|false*]> 屬性為 true 時應謹慎。

通常,只有在使用 Pivotal GemFire 的 Spring Data XML 名稱空間配置和引導新增到叢集的新非應用程式 Pivotal GemFire 伺服器時,才應啟用“自動重新連線”。換句話說,當 Pivotal GemFire 的 Spring Data 用於開發和構建碰巧也是 Pivotal GemFire 叢集的對等 Cache 成員的 Pivotal GemFire 應用程式時,不應啟用“自動重新連線”。

此限制的主要原因是,大多數 Pivotal GemFire 應用程式使用對 Pivotal GemFire Cache 或區域的引用來執行資料訪問操作。這些引用由 Spring 容器“注入”到應用程式元件(例如儲存庫)中,供應用程式使用。當對等成員被強制從叢集的其餘部分斷開連線時,可能是因為對等成員變得無響應或網路分割槽將一個或多個對等成員分離成一個太小而無法作為獨立分散式系統執行的組,對等成員會關閉,並且所有 Pivotal GemFire 元件引用(快取、區域等)都變得無效。

本質上,每個對等成員中當前的強制斷開處理邏輯會從頭開始拆除系統。JGroups 堆疊關閉,分散式系統進入關閉狀態,最後,快取關閉。實際上,所有記憶體引用都變得陳舊並丟失。

與分散式系統斷開連線後,對等成員進入“重新連線”狀態,並定期嘗試重新加入分散式系統。如果對等成員成功重新連線,該成員將從現有成員重建其分散式系統“檢視”,並接收新的分散式系統 ID。此外,所有快取、區域和其他 Pivotal GemFire 元件都將重新構建。因此,所有舊引用(可能已由 Spring 容器注入到應用程式中)現在都已陳舊且不再有效。

Pivotal GemFire 不保證(即使使用 Pivotal GemFire 公共 Java API)應用程式快取、區域或其他元件引用會透過重新連線操作自動重新整理。因此,Pivotal GemFire 應用程式必須注意重新整理自己的引用。

不幸的是,也沒有辦法收到斷開連線事件,也沒有辦法收到重新連線事件。如果是這樣,就會有一種乾淨的方法來知道何時呼叫 ConfigurableApplicationContext.refresh(),即使它適用於應用程式這樣做,這就是為什麼 Pivotal GemFire 的這個“功能”不建議用於對等 Cache 應用程式的原因。

有關“自動重新連線”的更多資訊,請參閱 Pivotal GemFire 的 產品文件

使用基於叢集的配置

Pivotal GemFire 的叢集配置服務是一種便捷的方式,任何加入叢集的對等成員都可以透過使用 Locator 維護的共享持久配置獲得叢集的“一致檢視”。使用基於叢集的配置可確保對等成員的配置在成員加入時與 Pivotal GemFire 分散式系統相容。

Pivotal GemFire 的 Spring Data 的此功能(將 use-cluster-configuration 屬性設定為 true)的工作方式與 cache-xml-location 屬性相同,只是 Pivotal GemFire 配置元資料的來源是透過 Locator 從網路獲取,而不是駐留在本地檔案系統中的原生 cache.xml 檔案。

所有 Pivotal GemFire 本機配置元資料,無論是來自 cache.xml 還是來自叢集配置服務,都將在任何 Spring (XML) 配置元資料之前應用。因此,Spring 的配置旨在“增強”本機 Pivotal GemFire 配置元資料,並且最有可能特定於應用程式。

再次,要啟用此功能,請在 Spring XML 配置中指定以下內容

<gfe:cache use-cluster-configuration="true"/>
雖然某些 Pivotal GemFire 工具(例如 Gfsh)在進行類似模式的更改時會“記錄”其操作(例如,gfsh>create region --name=Example --type=PARTITION),但 Pivotal GemFire 的 Spring Data 的配置元資料不會被記錄。直接使用 Pivotal GemFire 的公共 Java API 時也是如此。它也不會被記錄。

有關 Pivotal GemFire 叢集配置服務的更多資訊,請參閱產品文件

5.4.2. 配置 Pivotal GemFire CacheServer

Pivotal GemFire 的 Spring Data 包含對配置 CacheServer 的專用支援,允許透過 Spring 容器進行完整配置,如以下示例所示

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:gfe="https://www.springframework.org/schema/gemfire"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
    https://www.springframework.org/schema/gemfire https://www.springframework.org/schema/gemfire/spring-gemfire.xsd
">

  <gfe:cache/>

  <!-- Example depicting serveral Pivotal GemFire CacheServer configuration options -->
  <gfe:cache-server id="advanced-config" auto-startup="true"
       bind-address="localhost" host-name-for-clients="localhost" port="${gemfire.cache.server.port}"
       load-poll-interval="2000" max-connections="22" max-message-count="1000" max-threads="16"
       max-time-between-pings="30000" groups="test-server">

    <gfe:subscription-config eviction-type="ENTRY" capacity="1000" disk-store="file://${java.io.tmpdir}"/>

  </gfe:cache-server>

  <context:property-placeholder location="classpath:cache-server.properties"/>

</beans>

前面的配置顯示了 cache-server 元素和許多可用選項。

此配置不硬編碼埠,而是使用 Spring 的 context 名稱空間來宣告 property-placeholder屬性佔位符 讀取一個或多個屬性檔案,然後在執行時用值替換屬性佔位符。這樣做允許管理員更改值而無需接觸主應用程式配置。Spring 還提供了 SpEL 和一個 環境抽象 來支援將特定於環境的屬性從主程式碼庫中外部化,從而簡化了跨多臺機器的部署。
為避免初始化問題,Pivotal GemFire 的 Spring Data 啟動的 CacheServer 在 Spring 容器完全初始化後才啟動。這樣做允許宣告式定義的潛在區域、監聽器、寫入器或例項化器在伺服器開始接受連線之前完全初始化和註冊。在以程式設計方式配置這些元素時請記住這一點,因為伺服器可能在您的元件之前啟動,因此不會立即被連線的客戶端看到。

5.4.3. 配置 Pivotal GemFire ClientCache

除了定義 Pivotal GemFire 對等 Cache 之外,Pivotal GemFire 的 Spring Data 還支援在 Spring 容器中定義 Pivotal GemFire ClientCacheClientCache 定義在配置和使用上與 Pivotal GemFire 對等 快取 相似,並受 org.springframework.data.gemfire.client.ClientCacheFactoryBean 支援。

使用預設配置的 Pivotal GemFire 快取客戶端的最簡單定義如下

<beans>
  <gfe:client-cache/>
</beans>

client-cache 支援許多與 快取 元素相同的選項。但是,與功能完備的對等 Cache 成員不同,快取客戶端透過一個池連線到遠端快取伺服器。預設情況下,會建立一個池來連線到在 localhost 上執行並監聽埠 40404 的伺服器。除非區域配置為使用特定池,否則所有客戶端區域都使用預設池。

可以使用 pool 元素定義池。此客戶端池可用於配置直接連線到伺服器的單個實體,或透過一個或多個 Locator 連線到整個快取。

例如,要自定義 client-cache 使用的預設池,開發人員需要定義一個池並將其連線到快取定義,如以下示例所示

<beans>
  <gfe:client-cache id="myCache" pool-name="myPool"/>

  <gfe:pool id="myPool" subscription-enabled="true">
    <gfe:locator host="${gemfire.locator.host}" port="${gemfire.locator.port}"/>
  </gfe:pool>
</beans>

<client-cache> 元素還有一個 ready-for-events 屬性。如果該屬性設定為 true,則客戶端快取初始化將包含對 ClientCache.readyForEvents() 的呼叫。

客戶端區域 更詳細地介紹了客戶端配置。

Pivotal GemFire 的 DEFAULT 池和 Pivotal GemFire 的 Spring Data 池定義

如果 Pivotal GemFire ClientCache 僅為本地,則不需要池定義。例如,您可以定義以下內容

<gfe:client-cache/>

<gfe:client-region id="Example" shortcut="LOCAL"/>

在這種情況下,“示例”區域是 LOCAL,並且客戶端和伺服器之間不分發資料。因此,不需要池。這對於任何客戶端的本地區域都是如此,如 Pivotal GemFire 的 ClientRegionShortcut(所有 LOCAL_* 快捷方式)所定義。

但是,如果客戶端區域是伺服器端區域的(快取)代理,則需要一個池。在這種情況下,有幾種定義和使用池的方法。

ClientCache、一個池和一個基於代理的區域都已定義但未明確標識時,Pivotal GemFire 的 Spring Data 會自動解析引用,如以下示例所示

<gfe:client-cache/>

<gfe:pool>
  <gfe:locator host="${geode.locator.host}" port="${geode.locator.port}"/>
</gfe:pool>

<gfe:client-region id="Example" shortcut="PROXY"/>

在前面的示例中,ClientCache 被標識為 gemfireCache,Pool 被標識為 gemfirePool,客戶端區域被標識為“Example”。然而,ClientCachegemfirePool 初始化 Pivotal GemFire 的 DEFAULT Pool,並且客戶端區域在客戶端和伺服器之間分發資料時使用 gemfirePool

基本上,Pivotal GemFire 的 Spring Data 會將前面的配置解析為以下內容

<gfe:client-cache id="gemfireCache" pool-name="gemfirePool"/>

<gfe:pool id="gemfirePool">
  <gfe:locator host="${geode.locator.host}" port="${geode.locator.port}"/>
</gfe:pool>

<gfe:client-region id="Example" cache-ref="gemfireCache" pool-name="gemfirePool" shortcut="PROXY"/>

Pivotal GemFire 仍然會建立一個名為 DEFAULT 的池。Pivotal GemFire 的 Spring Data 會導致 DEFAULT 池從 gemfirePool 初始化。這在定義了多個池且客戶端區域使用單獨的池,或者根本不宣告池的情況下非常有用。

考慮以下情況

<gfe:client-cache pool-name="locatorPool"/>

<gfe:pool id="locatorPool">
  <gfe:locator host="${geode.locator.host}" port="${geode.locator.port}"/>
</gfe:pool>

<gfe:pool id="serverPool">
  <gfe:server host="${geode.server.host}" port="${geode.server.port}"/>
</gfe:pool>

<gfe:client-region id="Example" pool-name="serverPool" shortcut="PROXY"/>

<gfe:client-region id="AnotherExample" shortcut="CACHING_PROXY"/>

<gfe:client-region id="YetAnotherExample" shortcut="LOCAL"/>

在此設定中,Pivotal GemFire client-cache DEFAULT 池從 locatorPool 初始化,如 pool-name 屬性所指定。沒有 Spring Data for Pivotal GemFire 定義的 gemfirePool,因為這兩個池都被顯式標識(命名)——分別是 locatorPoolserverPool

“示例”區域明確引用並專門使用 serverPoolAnotherExample 區域使用 Pivotal GemFire 的 DEFAULT 池,該池再次根據客戶端快取 bean 定義的 pool-name 屬性從 locatorPool 配置。

最後,YetAnotherExample 區域不使用池,因為它是一個 LOCAL 區域。

AnotherExample 區域將首先查詢名為 gemfirePool 的池 bean,但這需要定義一個匿名池 bean(即 <gfe:pool/>)或一個顯式命名為 gemfirePool 的池 bean(例如,<gfe:pool id="gemfirePool"/>)。
如果我們將 locatorPool 的名稱更改為 gemfirePool 或將池 bean 定義設為匿名,其效果與前面的配置相同。

5.5. 配置區域

需要一個區域來儲存和檢索快取中的資料。org.apache.geode.cache.Region 是一個擴充套件 java.util.Map 的介面,允許使用熟悉的鍵值語義進行基本資料訪問。Region 介面被連線到需要它的應用程式類,因此實際的區域型別與程式設計模型解耦。通常,每個區域都與一個域物件關聯,類似於關係資料庫中的表。

Pivotal GemFire 實現以下型別的區域

  • REPLICATE - 資料在叢集中定義該區域的所有快取成員之間複製。這提供了非常高的讀取效能,但寫入執行復制需要更長時間。

  • PARTITION - 資料在叢集中定義該區域的許多快取成員之間分割槽(分片)到儲存桶中。這提供了高讀寫效能,適用於單個節點過大的大型資料集。

  • LOCAL - 資料僅存在於本地節點。

  • Client - 從技術上講,客戶端區域是一個 LOCAL 區域,它充當叢集中快取伺服器上託管的 REPLICATE 或 PARTITION 區域的 PROXY。它可以儲存本地建立或獲取的資料。或者,它可以是空的。本地更新與快取伺服器同步。此外,客戶端區域可以訂閱事件以保持與訪問同一伺服器區域的遠端程序引起的更改保持最新(同步)。

有關各種區域型別及其功能以及配置選項的更多資訊,請參閱 Pivotal GemFire 關於 區域型別 的文件。

5.5.1. 使用外部配置的區域

要引用已在 Pivotal GemFire 原生 cache.xml 檔案中配置的區域,請使用 lookup-region 元素。只需使用 name 屬性宣告目標區域名稱。例如,要為名為 Orders 的現有區域宣告一個標識為 ordersRegion 的 bean 定義,您可以使用以下 bean 定義

<gfe:lookup-region id="ordersRegion" name="Orders"/>

如果未指定 name,則 bean 的 id 將用作區域的名稱。上面的示例變為

<!-- lookup for a Region called 'Orders' -->
<gfe:lookup-region id="Orders"/>
如果區域不存在,將丟擲初始化異常。要配置新區域,請繼續閱讀下面的相應部分。

在前面的示例中,由於未顯式定義快取名稱,因此使用了預設命名約定 (gemfireCache)。或者,可以使用 cache-ref 屬性引用快取 bean

<gfe:cache id="myCache"/>
<gfe:lookup-region id="ordersRegion" name="Orders" cache-ref="myCache"/>

lookup-region 允許您檢索現有、預配置的區域,而無需公開區域語義或設定基礎設施。

5.5.2. 自動區域查詢

當您在 <gfe:cache> 元素上使用 cache-xml-location 屬性時,auto-region-lookup 允許您將 Pivotal GemFire 原生 cache.xml 檔案中定義的所有區域匯入到 Spring ApplicationContext 中。

例如,考慮以下 cache.xml 檔案

<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="https://geode.apache.org/schema/cache"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://geode.apache.org/schema/cache https://geode.apache.org/schema/cache/cache-1.0.xsd"
       version="1.0">

  <region name="Parent" refid="REPLICATE">
    <region name="Child" refid="REPLICATE"/>
  </region>

</cache>

您可以按如下方式匯入前面的 cache.xml 檔案

<gfe:cache cache-xml-location="cache.xml"/>

然後,您可以使用 <gfe:lookup-region> 元素(例如 <gfe:lookup-region id="Parent"/>)將特定的區域作為 bean 引用到 Spring 容器中,或者您可以透過使用以下方式匯入 cache.xml 中定義的所有區域

<gfe:auto-region-lookup/>

Pivotal GemFire 的 Spring Data 會自動為 cache.xml 中定義的所有尚未透過顯式 <gfe:lookup-region> bean 宣告新增到 Spring 容器的 Pivotal GemFire 區域建立 bean。

重要的是要認識到,Pivotal GemFire 的 Spring Data 使用 Spring BeanPostProcessor 在快取建立和初始化後對其進行後處理,以確定要作為 bean 新增到 Spring ApplicationContext 中的 Pivotal GemFire 中定義的區域。

您可以像注入 Spring ApplicationContext 中定義的任何其他 bean 一樣注入這些“自動查詢”的區域,但有一個例外:您可能需要定義與“gemfireCache”bean 的 depends-on 關聯,如下所示

package example;

import ...

@Repository("appDao")
@DependsOn("gemfireCache")
public class ApplicationDao extends DaoSupport {

    @Resource(name = "Parent")
    private Region<?, ?> parent;

    @Resource(name = "/Parent/Child")
    private Region<?, ?> child;

    ...
}

前面的示例僅適用於您使用 Spring 的 component-scan 功能的情況。

如果您使用 Spring XML 配置宣告元件,那麼您將執行以下操作

<bean class="example.ApplicationDao" depends-on="gemfireCache"/>

這樣做可以確保 Pivotal GemFire 快取和 cache.xml 中定義的所有區域在使用 <gfe:auto-region-lookup> 元素時,在任何具有自動連線引用的元件之前建立。

5.5.3. 配置區域

Pivotal GemFire 的 Spring Data 透過以下元素提供對配置任何型別區域的全面支援

  • LOCAL 區域:<local-region>

  • PARTITION 區域:<partitioned-region>

  • REPLICATE 區域:<replicated-region>

  • Client 區域:<client-region>

有關 區域型別 的全面描述,請參閱 Pivotal GemFire 文件。

常用區域屬性

下表列出了所有區域型別可用的屬性

表 1. 常用區域屬性
名稱 描述

cache-ref

Pivotal GemFire 快取 bean 引用

定義 Pivotal GemFire 快取的 bean 名稱(預設為 'gemfireCache')。

cloning-enabled

布林值(預設值:false

當為 true 時,更新將應用於值的克隆,然後將克隆儲存到快取。當為 false 時,值在快取中原地修改。

close

布林值(預設值:false

確定區域在關閉時是否應關閉。

concurrency-checks-enabled

布林值(預設值:true

確定成員是否執行檢查以提供對分散式區域併發或亂序更新的一致處理。

data-policy

請參閱 Pivotal GemFire 的 資料策略

區域的資料策略。請注意,並非所有區域型別都支援所有資料策略。

destroy

布林值(預設值:false

確定區域在關閉時是否應銷燬。

disk-store-ref

配置的磁碟儲存的名稱。

對透過 disk-store 元素建立的 bean 的引用。

disk-synchronous

布林值(預設值:true

確定磁碟儲存寫入是否同步。

id

任何有效的 bean 名稱。

如果未指定 name 屬性,則為預設區域名稱。

ignore-if-exists

布林值(預設值:false

如果區域已存在於快取中,則忽略此 bean 定義,轉而進行查詢。

ignore-jta

布林值(預設值:false

確定此區域是否參與 JTA (Java Transaction API) 事務。

index-update-type

synchronousasynchronous(預設值:synchronous

確定索引在條目建立時是同步還是非同步更新。

initial-capacity

整數(預設值:16)

區域條目數量的初始記憶體分配。

key-constraint

任何有效、完全限定的 Java 類名。

預期鍵型別。

load-factor

浮點數(預設值:.75)

設定用於儲存區域條目的底層 java.util.ConcurrentHashMap 的初始引數。

name

任何有效的區域名稱。

區域的名稱。如果未指定,則假定為 id 屬性的值(即 bean 名稱)。

persistent

*布林值(預設值:false

確定區域是否將條目持久化到本地磁碟(磁碟儲存)。

shortcut

請參閱 https://gemfire-98-javadocs.docs.pivotal.io//org/apache/geode/cache/RegionShortcut.html

此區域的 RegionShortcut。允許根據預定義預設值輕鬆初始化區域。

statistics

布林值(預設值:false

確定區域是否報告統計資訊。

template

區域模板的名稱。

對透過 *region-template 元素之一建立的 bean 的引用。

value-constraint

任何有效、完全限定的 Java 類名。

預期值型別。

CacheListener例項

CacheListener例項註冊到Region,以處理Region事件,例如條目建立、更新、銷燬等。CacheListener可以是實現CacheListener介面的任何bean。一個Region可以有多個監聽器,透過包含在*-region元素中的cache-listener元素宣告。

以下示例包含兩個宣告的CacheListener。第一個引用一個命名的頂層Spring bean。第二個是匿名內部bean定義。

<bean id="myListener" class="org.example.app.geode.cache.SimpleCacheListener"/>

<gfe:replicated-region id="regionWithListeners">
  <gfe:cache-listener>
    <!-- nested CacheListener bean reference -->
    <ref bean="myListener"/>
    <!-- nested CacheListener bean definition -->
    <bean class="org.example.app.geode.cache.AnotherSimpleCacheListener"/>
  </gfe:cache-listener>
</gfe:replicated-region>

以下示例使用帶有ref屬性的cache-listener元素的替代形式。當定義單個CacheListener時,這樣做可以實現更簡潔的配置。

注意:XML名稱空間只允許一個cache-listener元素,因此必須使用前面示例中所示的樣式或以下示例中所示的樣式。

<beans>
  <gfe:replicated-region id="exampleReplicateRegionWithCacheListener">
    <gfe:cache-listener ref="myListener"/>
  </gfe:replicated-region>

  <bean id="myListener" class="example.CacheListener"/>
</beans>
cache-listener元素中使用ref和巢狀宣告是非法的。這兩個選項是互斥的,在同一個元素中使用兩者會導致異常。
Bean引用約定

cache-listener元素是XML名稱空間中常用模式的一個示例,Pivotal GemFire在任何需要透過實現回撥介面來響應快取或區域事件呼叫自定義程式碼的地方都使用該模式。當您使用Spring的IoC容器時,實現是一個標準的Spring bean。為了簡化配置,模式允許cache-listener元素出現一次,但如果允許多個例項,它可以包含巢狀的bean引用和內部bean定義,以任何組合形式。約定是使用單數形式(即cache-listener而不是cache-listeners),反映了最常見的情況實際上是單個例項。我們已經在高階快取配置示例中看到了這種模式的示例。

CacheLoaders和CacheWriters

cache-listener類似,XML名稱空間提供了cache-loadercache-writer元素,用於為Region註冊這些Pivotal GemFire元件。

當快取未命中時,會呼叫CacheLoader,以便從外部資料來源(如資料庫)載入條目。在建立或更新條目之前,會呼叫CacheWriter,以允許將條目同步到外部資料來源。主要區別在於,Pivotal GemFire每個Region最多支援一個CacheLoaderCacheWriter例項。但是,可以使用任何一種宣告樣式。

以下示例聲明瞭一個同時具有CacheLoaderCacheWriter的Region

<beans>
  <gfe:replicated-region id="exampleReplicateRegionWithCacheLoaderAndCacheWriter">
    <gfe:cache-loader ref="myLoader"/>
    <gfe:cache-writer>
      <bean class="example.CacheWriter"/>
    </gfe:cache-writer>
  </gfe:replicated-region>

  <bean id="myLoader" class="example.CacheLoader">
    <property name="dataSource" ref="mySqlDataSource"/>
  </bean>

  <!-- DataSource bean definition -->
</beans>

有關更多詳細資訊,請參閱Pivotal GemFire文件中的CacheLoaderCacheWriter

5.5.4. 壓縮

Pivotal GemFire Region也可以被壓縮,以減少JVM記憶體消耗和壓力,從而可能避免全域性GC。當您為Region啟用壓縮時,儲存在記憶體中的所有Region值都將被壓縮,而鍵和索引保持未壓縮狀態。新值在放入Region時被壓縮,所有值在從Region讀取時自動解壓縮。值在持久化到磁碟或透過網路傳送到其他對等成員或客戶端時不會被壓縮。

以下示例顯示了一個啟用壓縮的Region

<beans>
  <gfe:replicated-region id="exampleReplicateRegionWithCompression">
    <gfe:compressor>
      <bean class="org.apache.geode.compression.SnappyCompressor"/>
    </gfe:compressor>
  </gfe:replicated-region>
</beans>

有關Region壓縮的更多資訊,請參閱Pivotal GemFire的文件。

5.5.5. 堆外記憶體

Pivotal GemFire Region也可以配置為將Region值儲存在堆外記憶體中,這部分JVM記憶體不受垃圾回收(GC)的影響。透過避免昂貴的GC週期,您的應用程式可以將更多時間花在重要的事務上,例如處理請求。

使用堆外記憶體就像宣告要使用的記憶體量,然後啟用您的Region使用堆外記憶體一樣簡單,如以下配置所示

<util:properties id="gemfireProperties">
    <prop key="off-heap-memory-size">200G</prop>
</util:properties>

<gfe:cache properties-ref="gemfireProperties"/>

<gfe:partitioned-region id="ExampleOffHeapRegion" off-heap="true"/>

您可以透過使用<gfe:cache>元素設定以下Pivotal GemFire配置屬性來控制堆外記憶體管理的其他方面:

<gfe:cache critical-off-heap-percentage="90" eviction-off-heap-percentage"80"/>

Pivotal GemFire的ResourceManager將使用這兩個閾值(critical-off-heap-percentageeviction-off-heap-percentage)更有效地管理堆外記憶體,就像JVM管理堆記憶體一樣。Pivotal GemFire ResourceManager將透過驅逐舊資料來防止快取消耗過多的堆外記憶體。如果堆外管理器無法跟上,則ResourceManager會拒絕向快取新增內容,直到堆外記憶體管理器釋放了足夠的記憶體。

有關管理堆和堆外記憶體的更多資訊,請參閱Pivotal GemFire的文件。

具體來說,請閱讀管理堆外記憶體部分。

5.5.6. 子區域

Spring Data for Pivotal GemFire 還支援子區域,允許區域以分層關係排列。

例如,Pivotal GemFire 允許一個/Customer/Address區域和一個不同的/Employee/Address區域。此外,一個子區域可以擁有自己的子區域和配置。子區域不繼承父區域的屬性。區域型別可以混合搭配,但受 Pivotal GemFire 約束。子區域自然地宣告為區域的子元素。子區域的name屬性是簡單名稱。前面的示例可以配置如下:

<beans>
  <gfe:replicated-region name="Customer">
    <gfe:replicated-region name="Address"/>
  </gfe:replicated-region>

  <gfe:replicated-region name="Employee">
    <gfe:replicated-region name="Address"/>
  </gfe:replicated-region>
</beans>

請注意,子區域不允許使用Monospaced ([id])屬性。子區域是使用bean名稱建立的(在本例中分別為/Customer/Address和/Employee/Address)。因此,它們可以注入到其他應用程式bean中,例如GemfireTemplate,這些bean需要它們時可以使用區域的完整路徑名。區域的完整路徑名也應在OQL查詢字串中使用。

5.5.7. 區域模板

Spring Data for Pivotal GemFire 還支援區域模板。

此功能允許開發人員一次性定義通用的區域配置和屬性,並在 Spring ApplicationContext 中宣告的許多區域 bean 定義中重用該配置。

Spring Data for Pivotal GemFire 在其名稱空間中包含五個區域模板標籤

表 2. 區域模板標籤
標籤名 描述

<gfe:region-template>

定義通用的泛型區域屬性。擴充套件XML名稱空間中的regionType

<gfe:local-region-template>

定義通用“本地”區域屬性。擴充套件XML名稱空間中的localRegionType

<gfe:partitioned-region-template>

定義通用“分割槽”區域屬性。擴充套件XML名稱空間中的partitionedRegionType

<gfe:replicated-region-template>

定義通用“複製”區域屬性。擴充套件XML名稱空間中的replicatedRegionType

<gfe:client-region-template>

定義通用“客戶端”區域屬性。擴充套件XML名稱空間中的clientRegionType

除了標籤,具體的<gfe:*-region>元素(以及抽象的<gfe:*-region-template>元素)都有一個template屬性,用於定義區域繼承其配置的區域模板。區域模板甚至可以繼承其他區域模板。

以下示例顯示了一種可能的配置

<beans>
  <gfe:async-event-queue id="AEQ" persistent="false" parallel="false" dispatcher-threads="4">
    <gfe:async-event-listener>
      <bean class="example.AeqListener"/>
    </gfe:async-event-listener>
  </gfe:async-event-queue>

  <gfe:region-template id="BaseRegionTemplate" initial-capacity="51" load-factor="0.85" persistent="false" statistics="true"
      key-constraint="java.lang.Long" value-constraint="java.lang.String">
    <gfe:cache-listener>
      <bean class="example.CacheListenerOne"/>
      <bean class="example.CacheListenerTwo"/>
    </gfe:cache-listener>
    <gfe:entry-ttl timeout="600" action="DESTROY"/>
    <gfe:entry-tti timeout="300 action="INVLIDATE"/>
  </gfe:region-template>

  <gfe:region-template id="ExtendedRegionTemplate" template="BaseRegionTemplate" load-factor="0.55">
    <gfe:cache-loader>
      <bean class="example.CacheLoader"/>
    </gfe:cache-loader>
    <gfe:cache-writer>
      <bean class="example.CacheWriter"/>
    </gfe:cache-writer>
    <gfe:async-event-queue-ref bean="AEQ"/>
  </gfe:region-template>

  <gfe:partitioned-region-template id="PartitionRegionTemplate" template="ExtendedRegionTemplate"
      copies="1" load-factor="0.70" local-max-memory="1024" total-max-memory="16384" value-constraint="java.lang.Object">
    <gfe:partition-resolver>
      <bean class="example.PartitionResolver"/>
    </gfe:partition-resolver>
    <gfe:eviction type="ENTRY_COUNT" threshold="8192000" action="OVERFLOW_TO_DISK"/>
  </gfe:partitioned-region-template>

  <gfe:partitioned-region id="TemplateBasedPartitionRegion" template="PartitionRegionTemplate"
      copies="2" local-max-memory="8192" persistent="true" total-buckets="91"/>
</beans>

區域模板也適用於子區域。請注意,'TemplateBasedPartitionRegion' 擴充套件了 'PartitionRegionTemplate',後者又擴充套件了 'ExtendedRegionTemplate',而後者又擴充套件了 'BaseRegionTemplate'。在後續繼承的區域 bean 定義中定義的屬性和子元素會覆蓋父級中的內容。

模板的工作原理

Spring Data for Pivotal GemFire 在解析 Spring ApplicationContext 配置元資料時應用區域模板,因此,區域模板必須按繼承順序宣告。換句話說,父模板必須在子模板之前定義。這樣做可以確保應用正確的配置,尤其是在元素屬性或子元素被覆蓋時。

同樣重要的是要記住,區域型別只能從其他類似型別的區域繼承。例如,<gfe:replicated-region>不可能從<gfe:partitioned-region-template>繼承。
區域模板是單一繼承的。
關於區域、子區域和查詢的注意事項

以前,Spring Data for Pivotal GemFire XML 名稱空間中 replicated-regionpartitioned-regionlocal-regionclient-region 元素的一個底層屬性是先執行查詢,然後再嘗試建立區域。這樣做是為了防止區域已經存在的情況,如果區域是在匯入的 Pivotal GemFire 本機 cache.xml 配置檔案中定義的,就會出現這種情況。因此,先執行查詢是為了避免任何錯誤。這是設計使然,可能會發生變化。

此行為已更改,預設行為現在是先建立Region。如果Region已經存在,則建立邏輯會快速失敗並丟擲適當的異常。但是,就像CREATE TABLE IF NOT EXISTS …​ DDL 語法一樣,Spring Data for Pivotal GemFire <gfe:*-region> XML名稱空間元素現在包含一個ignore-if-exists屬性,該屬性透過在嘗試建立Region之前,首先根據名稱查詢現有Region來恢復舊的行為。如果根據名稱找到現有Region並且ignore-if-exists設定為true,則Spring配置中定義的Region bean定義將被忽略。

Spring 團隊強烈建議,replicated-regionpartitioned-regionlocal-regionclient-region XML 名稱空間元素應嚴格用於僅定義新區域。當這些元素定義的區域已經存在並且區域元素首先執行查詢時,可能會出現一個問題是,如果您在應用程式配置中為驅逐、過期、訂閱等定義了不同的區域語義和行為,那麼區域定義可能不匹配,並可能表現出與應用程式要求相反的行為。更糟糕的是,您可能希望將區域定義為分散式區域(例如,PARTITION),而實際上,現有區域定義僅限於本地。
推薦實踐 - 僅使用replicated-regionpartitioned-regionlocal-regionclient-region XML 名稱空間元素來定義新區域。

考慮以下 Pivotal GemFire 本機 cache.xml 配置檔案

<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="https://geode.apache.org/schema/cache"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://geode.apache.org/schema/cache https://geode.apache.org/schema/cache/cache-1.0.xsd"
       version="1.0">

  <region name="Customers" refid="REPLICATE">
    <region name="Accounts" refid="REPLICATE">
      <region name="Orders" refid="REPLICATE">
        <region name="Items" refid="REPLICATE"/>
      </region>
    </region>
  </region>

</cache>

此外,考慮您可能已將應用程式 DAO 定義如下:

public class CustomerAccountDao extends GemDaoSupport {

    @Resource(name = "Customers/Accounts")
    private Region customersAccounts;

    ...
}

在這裡,我們將對Customers/Accounts Region的引用注入到我們的應用程式DAO中。因此,開發人員在Spring XML配置元資料中為部分或所有這些Region定義bean的情況並不少見,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:gfe="https://www.springframework.org/schema/gemfire"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    https://www.springframework.org/schema/gemfire https://www.springframework.org/schema/gemfire/spring-gemfire.xsd
">

  <gfe:cache cache-xml-location="classpath:cache.xml"/>

  <gfe:lookup-region name="Customers/Accounts"/>
  <gfe:lookup-region name="Customers/Accounts/Orders"/>

</beans>

Customers/AccountsCustomers/Accounts/Orders區域在Spring容器中分別作為Customers/AccountsCustomers/Accounts/Orders引用。使用lookup-region元素和相應的語法(前面描述的)的好處是,它允許您直接引用子區域,而無需不必要地為父區域(在本例中為Customers)定義bean。

考慮以下糟糕的示例,它將配置元資料語法更改為使用巢狀格式

<gfe:lookup-region name="Customers">
  <gfe:lookup-region name="Accounts">
    <gfe:lookup-region name="Orders"/>
  </gfe:lookup-region>
</gfe:lookup-region>

現在考慮另一個糟糕的示例,它使用頂級replicated-region元素以及設定為首先執行查詢的ignore-if-exists屬性。

<gfe:replicated-region name="Customers" persistent="true" ignore-if-exists="true">
  <gfe:replicated-region name="Accounts" persistent="true" ignore-if-exists="true">
    <gfe:replicated-region name="Orders" persistent="true" ignore-if-exists="true"/>
  </gfe:replicated-region>
</gfe:replicated-region>

在Spring ApplicationContext中定義的Region bean包括:{ "Customers", "/Customers/Accounts", "/Customers/Accounts/Orders" }。這意味著前面示例中顯示的依賴注入引用(即@Resource(name = "Customers/Accounts"))現在已損壞,因為實際上沒有定義名為Customers/Accounts的bean。因此,您不應按照前面兩個示例所示配置Region。

Pivotal GemFire在引用父區域和子區域時非常靈活,無論是否帶有前導斜槓。例如,父級可以引用為/CustomersCustomers,子級可以引用為/Customers/AccountsCustomers/Accounts。但是,Spring Data for Pivotal GemFire在根據區域命名bean時非常具體。它始終使用斜槓 (/) 來表示子區域(例如,/Customers/Accounts)。

因此,您應該使用前面所示的非巢狀lookup-region語法,或者定義帶前導斜槓 (/) 的直接引用,如下所示:

<gfe:lookup-region name="/Customers/Accounts"/>
<gfe:lookup-region name="/Customers/Accounts/Orders"/>

前面的示例,其中使用了巢狀的replicated-region元素來引用子區域,顯示了前面所述的問題。Customers、Accounts和Orders區域和子區域是否持久?它們不是持久的,因為區域是在本機 Pivotal GemFire cache.xml 配置檔案中定義為REPLICATE,並且在快取bean初始化之前(一旦<gfe:cache>元素被處理)就已存在。

5.5.8. 資料驅逐(帶溢位)

基於各種約束,每個Region都可以有一個逐出策略,用於從記憶體中逐出資料。目前,在Pivotal GemFire中,逐出適用於最近最少使用的條目(也稱為LRU)。被逐出的條目要麼被銷燬,要麼被分頁到磁碟(稱為“溢位到磁碟”)。

Spring Data for Pivotal GemFire 透過使用巢狀的 eviction 元素支援 PARTITION 區域、REPLICATE 區域以及客戶端、本地區域的所有逐出策略(條目計數、記憶體和堆使用情況)。

例如,要配置一個PARTITION Region,使其在記憶體大小超過512 MB時溢位到磁碟,您可以指定以下配置

<gfe:partitioned-region id="examplePartitionRegionWithEviction">
  <gfe:eviction type="MEMORY_SIZE" threshold="512" action="OVERFLOW_TO_DISK"/>
</gfe:partitioned-region>
副本不能使用local destroy驅逐,因為那會使它們失效。有關更多資訊,請參閱Pivotal GemFire文件。

配置溢位區域時,應透過disk-store元素配置儲存以實現最大效率。

有關驅逐策略的詳細描述,請參閱Pivotal GemFire文件中關於驅逐的部分。

5.5.9. 資料過期

Pivotal GemFire 允許您控制條目在快取中存在多長時間。過期是由經過時間驅動的,而逐出是由條目計數或堆或記憶體使用情況驅動的。一旦條目過期,就無法再從快取中訪問它。

Pivotal GemFire 支援以下過期型別

  • 存活時間 (TTL):物件在上次建立或更新後可以在快取中保留的秒數。對於條目,建立和put操作將計數器設定為零。區域計數器在區域建立時和條目計數器重置時重置。

  • 空閒超時 (TTI):物件在上次訪問後可以在快取中保留的秒數。物件的空閒超時計數器在其TTL計數器重置的任何時候都會重置。此外,條目的空閒超時計數器在透過get操作或netSearch訪問條目的任何時候都會重置。區域的空閒超時計數器在其任何條目的空閒超時重置時都會重置。

這些都可以應用於Region本身或Region中的條目。Spring Data for Pivotal GemFire 提供了<region-ttl><region-tti><entry-ttl><entry-tti> Region子元素來指定超時值和過期操作。

以下示例顯示了一個設定了過期值的PARTITION Region

<gfe:partitioned-region id="examplePartitionRegionWithExpiration">
  <gfe:region-ttl timeout="30000" action="INVALIDATE"/>
  <gfe:entry-tti timeout="600" action="LOCAL_DESTROY"/>
</gfe:replicated-region>

有關過期策略的詳細描述,請參閱Pivotal GemFire文件中關於過期的部分。

基於註解的資料過期

使用 Spring Data for Pivotal GemFire,您可以在單個 Region 條目值(或者換句話說,直接在應用程式域物件上)定義過期策略和設定。例如,您可以在基於 Session 的應用程式域物件上定義過期策略,如下所示:

@Expiration(timeout = "1800", action = "INVALIDATE")
public class SessionBasedApplicationDomainObject {
  ...
}

您還可以透過使用@IdleTimeoutExpiration@TimeToLiveExpiration註解分別指定針對空閒超時(TTI)和存活時間(TTL)過期的特定設定,如以下示例所示

@TimeToLiveExpiration(timeout = "3600", action = "LOCAL_DESTROY")
@IdleTimeoutExpiration(timeout = "1800", action = "LOCAL_INVALIDATE")
@Expiration(timeout = "1800", action = "INVALIDATE")
public class AnotherSessionBasedApplicationDomainObject {
  ...
}

當指定多個過期註解型別時,@IdleTimeoutExpiration@TimeToLiveExpiration都優先於通用@Expiration註解,如前面示例所示。@IdleTimeoutExpiration@TimeToLiveExpiration都不會覆蓋另一個。相反,當配置不同的Region條目過期策略(例如TTL和TTI)時,它們是相互補充的。

所有基於@Expiration的註解僅適用於Region條目值。Region的過期不在Spring Data for Pivotal GemFire的過期註解支援範圍內。但是,Pivotal GemFire和Spring Data for Pivotal GemFire確實允許您使用SDG XML名稱空間設定Region過期,如下所示:

<gfe:*-region id="Example" persistent="false">
  <gfe:region-ttl timeout="600" action="DESTROY"/>
  <gfe:region-tti timeout="300" action="INVALIDATE"/>
</gfe:*-region>

Spring Data for Pivotal GemFire的@Expiration註解支援是使用Pivotal GemFire的CustomExpiry介面實現的。有關更多詳細資訊,請參閱Pivotal GemFire文件中關於配置資料過期的部分。

Spring Data for Pivotal GemFire 的 AnnotationBasedExpiration 類(和 CustomExpiry 實現)負責處理 SDG @Expiration 註解,並根據請求適當應用區域條目過期的過期策略配置。

要使用 Spring Data for Pivotal GemFire 配置特定的 Pivotal GemFire 區域,以將過期策略適當地應用於使用基於 @Expiration 註解的應用程式域物件,您必須:

  1. 透過使用適當的建構函式或便捷的工廠方法之一,在 Spring ApplicationContext 中定義一個型別為 AnnotationBasedExpiration 的 bean。當配置特定過期型別(例如空閒超時 (TTI) 或存活時間 (TTL))的過期時,您應該使用 AnnotationBasedExpiration 類中的工廠方法之一,如下所示:

    <bean id="ttlExpiration" class="org.springframework.data.gemfire.expiration.AnnotationBasedExpiration"
          factory-method="forTimeToLive"/>
    
    <gfe:partitioned-region id="Example" persistent="false">
        <gfe:custom-entry-ttl ref="ttlExpiration"/>
    </gfe:partitioned-region>

    要配置空閒超時(TTI)過期,請使用forIdleTimeout工廠方法和<gfe:custom-entry-tti ref="ttiExpiration"/>元素來設定TTI。

  2. (可選)使用 Spring Data for Pivotal GemFire 的 @Expiration 註解之一:@Expiration@IdleTimeoutExpiration@TimeToLiveExpiration,為儲存在區域中的應用程式域物件新增帶有過期策略和自定義設定的註解。

  3. (可選)在某些情況下,如果特定的應用程式域物件根本沒有用 Spring Data for Pivotal GemFire 的 @Expiration 註解進行註解,但 Pivotal GemFire 區域被配置為使用 SDG 的自定義 AnnotationBasedExpiration 類來確定儲存在區域中的物件的過期策略和設定,您可以透過執行以下操作來設定 AnnotationBasedExpiration bean 上的“預設”過期屬性:

<bean id="defaultExpirationAttributes" class="org.apache.geode.cache.ExpirationAttributes">
    <constructor-arg value="600"/>
    <constructor-arg value="#{T(org.apache.geode.cache.ExpirationAction).DESTROY}"/>
</bean>

<bean id="ttiExpiration" class="org.springframework.data.gemfire.expiration.AnnotationBasedExpiration"
      factory-method="forIdleTimeout">
    <constructor-arg ref="defaultExpirationAttributes"/>
</bean>

<gfe:partitioned-region id="Example" persistent="false">
    <gfe:custom-entry-tti ref="ttiExpiration"/>
</gfe:partitioned-region>

您可能已經注意到,Spring Data for Pivotal GemFire 的 @Expiration 註解使用 String 作為屬性型別,而不是(可能更合適地)強型別——例如,'timeout' 為 int,'action' 為 SDG 的 ExpirationActionType。為什麼會這樣呢?

好了,我們來看 Spring Data for Pivotal GemFire 的另一個特性,它利用 Spring 的核心基礎設施來方便配置:屬性佔位符和 Spring Expression Language (SpEL) 表示式。

例如,開發人員可以使用@Expiration註解屬性中的屬性佔位符來指定過期“timeout”和“action”,如下例所示:

@TimeToLiveExpiration(timeout = "${geode.region.entry.expiration.ttl.timeout}"
    action = "${geode.region.entry.expiration.ttl.action}")
public class ExampleApplicationDomainObject {
  ...
}

然後,在您的 Spring XML 配置或 JavaConfig 中,您可以宣告以下 bean:

<util:properties id="expirationSettings">
  <prop key="geode.region.entry.expiration.ttl.timeout">600</prop>
  <prop key="geode.region.entry.expiration.ttl.action">INVALIDATE</prop>
  ...
</util:properties>

<context:property-placeholder properties-ref="expirationProperties"/>

這在多個應用程式域物件可能共享相似過期策略以及希望外部化配置時都非常方便。

但是,您可能需要更動態的過期配置,由執行系統的狀態決定。這時 SpEL 的強大功能就發揮作用了,實際上,這也是推薦的方法。您不僅可以引用 Spring 容器中的 bean 並訪問 bean 屬性、呼叫方法等,而且過期“timeout”和“action”的值可以是強型別的。考慮以下示例(它建立在前面的示例之上):

<util:properties id="expirationSettings">
  <prop key="geode.region.entry.expiration.ttl.timeout">600</prop>
  <prop key="geode.region.entry.expiration.ttl.action">#{T(org.springframework.data.gemfire.expiration.ExpirationActionType).DESTROY}</prop>
  <prop key="geode.region.entry.expiration.tti.action">#{T(org.apache.geode.cache.ExpirationAction).INVALIDATE}</prop>
  ...
</util:properties>

<context:property-placeholder properties-ref="expirationProperties"/>

然後,在您的應用程式域物件上,您可以定義超時和操作,如下所示:

@TimeToLiveExpiration(timeout = "@expirationSettings['geode.region.entry.expiration.ttl.timeout']"
    action = "@expirationSetting['geode.region.entry.expiration.ttl.action']")
public class ExampleApplicationDomainObject {
  ...
}

您可以想象,'expirationSettings' bean 可以是一個比簡單的java.util.Properties例項更有趣和有用的物件。在前面的示例中,properties元素(expirationSettings)使用SpEL將操作值基於實際的ExpirationAction列舉型別,如果列舉型別發生變化,可以迅速發現故障。

舉例來說,所有這些都在Spring Data for Pivotal GemFire測試套件中得到演示和測試。有關更多詳細資訊,請參閱原始碼

5.5.10. 資料永續性

區域可以是持久的。Pivotal GemFire 確保您放入配置為永續性的區域中的所有資料都以可恢復的方式寫入磁碟,以便您下次重新建立區域時可以恢復資料。這樣做允許在機器或程序故障後,甚至在有序關閉和隨後重新啟動 Pivotal GemFire 資料節點後恢復資料。

要使用Spring Data for Pivotal GemFire啟用永續性,請在任何<*-region>元素上將persistent屬性設定為true,如以下示例所示:

<gfe:partitioned-region id="examplePersitentPartitionRegion" persistent="true"/>

永續性也可以透過設定data-policy屬性來配置。為此,請將屬性的值設定為Pivotal GemFire的DataPolicy設定之一,如以下示例所示:

<gfe:partitioned-region id="anotherExamplePersistentPartitionRegion" data-policy="PERSISTENT_PARTITION"/>

DataPolicy必須與Region型別匹配,並且如果persistent屬性也明確設定,則必須與persistent屬性一致。如果persistent屬性設定為false但指定了永續性DataPolicy(例如PERSISTENT_REPLICATEPERSISTENT_PARTITION),則會丟擲初始化異常。

為了在持久化區域時達到最大效率,您應該透過disk-store元素配置儲存。DiskStore透過disk-store-ref屬性引用。此外,區域可以同步或非同步執行磁碟寫入。以下示例顯示了一個同步DiskStore

<gfe:partitioned-region id="yetAnotherExamplePersistentPartitionRegion" persistent="true"
    disk-store-ref="myDiskStore" disk-synchronous="true"/>

這在配置DiskStore中進一步討論。

5.5.11. 訂閱策略

Pivotal GemFire 允許配置點對點(P2P)事件訊息來控制區域接收的條目事件。Spring Data for Pivotal GemFire 提供<gfe:subscription/>子元素來將REPLICATEPARTITION區域的訂閱策略設定為ALLCACHE_CONTENT。以下示例顯示了一個區域,其訂閱策略設定為CACHE_CONTENT

<gfe:partitioned-region id="examplePartitionRegionWithCustomSubscription">
  <gfe:subscription type="CACHE_CONTENT"/>
</gfe:partitioned-region>

5.5.12. 本地區域

Spring Data for Pivotal GemFire 提供了一個專門的local-region元素用於建立本地Region。顧名思義,本地Region是獨立的,這意味著它們不與其他分散式系統成員共享資料。除此之外,所有常見的Region配置選項都適用。

以下示例顯示了一個最小宣告(同樣,該示例依賴於Spring Data for Pivotal GemFire XML命名約定來連線快取)

<gfe:local-region id="exampleLocalRegion"/>

在前面的示例中,建立了一個本地區域(如果不存在同名區域)。該區域的名稱與bean ID(exampleLocalRegion)相同,並且該bean假定存在一個名為gemfireCache的Pivotal GemFire快取。

5.5.13. 複製區域

一種常見的區域型別是REPLICATE區域或“副本”。簡而言之,當一個區域被配置為REPLICATE時,每個託管該區域的成員都在本地儲存該區域條目的副本。對REPLICATE區域的任何更新都會分發到該區域的所有副本。當建立副本時,它會經歷一個初始化階段,在該階段它會發現其他副本並自動複製所有條目。在一個副本初始化時,您仍然可以繼續使用其他副本。

所有常見的配置選項都適用於REPLICATE區域。Spring Data for Pivotal GemFire 提供了一個replicated-region元素。以下示例顯示了一個最小宣告:

<gfe:replicated-region id="exampleReplica"/>

有關更多詳細資訊,請參閱Pivotal GemFire文件中關於分散式和複製區域的部分。

5.5.14. 分割槽區域

Spring Data for Pivotal GemFire XML 名稱空間還支援PARTITION區域。

引用Pivotal GemFire文件:

“分割槽區域是指資料在託管該區域的對等伺服器之間進行劃分,以便每個對等伺服器儲存資料的一個子集。使用分割槽區域時,應用程式會看到一個邏輯檢視,該檢視看起來像一個包含該區域所有資料的單個對映。對此對映的讀寫操作會透明地路由到託管操作目標條目的對等伺服器。Pivotal GemFire 將雜湊碼域劃分為桶。每個桶分配給一個特定的對等伺服器,但可以隨時重新定位到另一個對等伺服器,以提高整個叢集的資源利用率。”

使用partitioned-region元素建立一個PARTITION區域。其配置選項類似於replicated-region,並增加了分割槽特定的功能,例如冗餘副本的數量、總最大記憶體、桶的數量、分割槽解析器等。

以下示例顯示瞭如何設定具有兩個冗餘副本的PARTITION區域

<gfe:partitioned-region id="examplePartitionRegion" copies="2" total-buckets="17">
  <gfe:partition-resolver>
    <bean class="example.PartitionResolver"/>
  </gfe:partition-resolver>
</gfe:partitioned-region>

有關更多詳細資訊,請參閱Pivotal GemFire文件中關於分割槽區域的部分。

分割槽區域屬性

下表快速概述了PARTITION區域特有的配置選項。這些選項是對前面描述的通用區域配置選項的補充。

表 3. partitioned-region 屬性
名稱 描述

副本

0..4

每個分割槽用於高可用性的副本數量。預設情況下,不建立副本,這意味著沒有冗餘。每個副本都以額外儲存為代價提供額外備份。

colocated-with

有效區域名稱

此新建立的PARTITION區域與哪個PARTITION區域並置的名稱。

local-max-memory

正整數

此程序中區域使用的最大記憶體量(以兆位元組為單位)。

total-max-memory

任意整數值

所有程序中區域使用的最大記憶體量(以兆位元組為單位)。

partition-listener

bean 名稱

此區域用於處理分割槽事件的PartitionListener的名稱。

partition-resolver

bean 名稱

此區域用於自定義分割槽的PartitionResolver的名稱。

recovery-delay

任意長整型值

現有成員在另一個成員崩潰後等待滿足冗餘的延遲(以毫秒為單位)。-1(預設值)表示故障後不恢復冗餘。

startup-recovery-delay

任意長整型值

新成員在滿足冗餘之前等待的毫秒數。-1 表示新增新成員不會觸發冗餘恢復。預設是在新增新成員時立即恢復冗餘。

5.5.15. 客戶端區域

Pivotal GemFire 支援各種部署拓撲來管理和分發資料。Pivotal GemFire 拓撲的主題超出了本文件的範圍。但是,快速回顧一下,Pivotal GemFire 支援的拓撲可以分為:點對點 (p2p)、客戶端-伺服器和廣域網 (WAN)。在後兩種配置中,通常會宣告連線到快取伺服器的客戶端區域。

Spring Data for Pivotal GemFire 透過其客戶端快取元素:client-regionpool,為每種配置提供專門支援。顧名思義,client-region定義了一個客戶端區域,而pool定義了一個由各種客戶端區域使用和共享的連線池。

以下示例顯示了一個典型的客戶端區域配置

<bean id="myListener" class="example.CacheListener"/>

<!-- client Region using the default SDG gemfirePool Pool -->
<gfe:client-region id="Example">
  <gfe:cache-listener ref="myListener"/>
</gfe:client-region>

<!-- client Region using its own dedicated Pool -->
<gfe:client-region id="AnotherExample" pool-name="myPool">
  <gfe:cache-listener ref="myListener"/>
</gfe:client-region>

<!-- Pool definition -->
<gfe:pool id="myPool" subscription-enabled="true">
  <gfe:locator host="remoteHost" port="12345"/>
</gfe:pool>

與其他區域型別一樣,client-region支援CacheListener例項以及CacheLoaderCacheWriter。它還需要一個連線Pool才能連線到一組定位器或伺服器。每個客戶端區域都可以有自己的Pool,或者它們可以共享同一個Pool。如果未指定Pool,則將使用“DEFAULT”Pool

在前面的示例中,Pool配置了一個Locator。Locator是一個單獨的程序,用於發現分散式系統中的快取伺服器和對等資料成員,建議用於生產系統。還可以配置Pool以使用server元素直接連線到一個或多個快取伺服器。

有關客戶端上(特別是Pool上)可設定的選項的完整列表,請參閱 Spring Data for Pivotal GemFire 模式(“Spring Data for Pivotal GemFire 模式”)和 Pivotal GemFire 文件中關於客戶端-伺服器配置的部分。

客戶興趣

為了最大限度地減少網路流量,每個客戶端可以單獨定義自己的“興趣”策略,向Pivotal GemFire指示它實際需要的資料。在Spring Data for Pivotal GemFire中,可以為每個客戶端Region單獨定義“興趣”。支援基於鍵和基於正則表示式的興趣型別。

以下示例顯示了基於鍵和基於正則表示式的interest型別

<gfe:client-region id="Example" pool-name="myPool">
    <gfe:key-interest durable="true" result-policy="KEYS">
        <bean id="key" class="java.lang.String">
             <constructor-arg value="someKey"/>
        </bean>
    </gfe:key-interest>
    <gfe:regex-interest pattern=".*" receive-values="false"/>
</gfe:client-region>

特殊鍵ALL_KEYS表示已註冊所有鍵的“興趣”。使用正則表示式".*"可以實現相同目的。

<gfe:*-interest>鍵和正則表示式元素支援三個屬性:durablereceive-valuesresult-policy

durable指示當客戶端連線到叢集中的一個或多個伺服器時為客戶端建立的“興趣”策略和訂閱佇列是否在客戶端會話之間保持。如果客戶端斷開連線並重新連線,則在客戶端斷開連線期間,伺服器上為客戶端維護一個durable訂閱佇列。當客戶端重新連線時,客戶端會收到在客戶端與叢集中的伺服器斷開連線期間發生的任何事件。

叢集中的伺服器上為客戶端定義的每個連線Pool都會維護一個訂閱佇列,該Pool也已“啟用”訂閱。訂閱佇列用於儲存(並可能合併)傳送到客戶端的事件。如果訂閱佇列是durable的,它會在客戶端會話(即連線)之間持久化,可能直到指定的超時。如果客戶端未在給定時間範圍內返回,則客戶端Pool訂閱佇列將被銷燬,以減少叢集中伺服器的資源消耗。如果訂閱佇列不是durable的,它會在客戶端斷開連線時立即銷燬。您需要決定客戶端是應該接收在斷開連線期間發生的事件,還是隻需要在重新連線後接收最新事件。

receive-values屬性指示是否為建立和更新事件接收條目值。如果為true,則接收值。如果為false,則僅接收失效事件。

最後,`result-policy`是列舉型別:`KEYS`、`KEYS_VALUE`和`NONE`。預設值為`KEYS_VALUES`。`result-policy`控制客戶端首次連線以初始化本地快取時的初始轉儲,實質上是為客戶端播種與興趣策略匹配的所有條目的事件。

如前所述,如果沒有啟用Pool上的訂閱,客戶端興趣註冊作用不大。實際上,在沒有啟用訂閱的情況下嘗試興趣註冊是錯誤的。以下示例顯示瞭如何進行操作:

<gfe:pool ... subscription-enabled="true">
  ...
</gfe:pool>

除了subscription-enabled,您還可以設定subscription-ack-intervalsubscription-message-tracking-timeoutsubscription-redundancysubscription-redundancy用於控制叢集中的伺服器應維護多少個訂閱佇列副本。如果冗餘大於1,並且“主”訂閱佇列(即伺服器)宕機,則“輔助”訂閱佇列將接管,防止客戶端在HA場景中丟失事件。

除了Pool設定外,伺服器端區域還使用一個附加屬性enable-subscription-conflation來控制傳送到客戶端的事件的合併。這也可以進一步最小化網路流量,並且在應用程式只關心條目最新值的情況下非常有用。但是,如果應用程式保留了發生的事件時間序列,合併將阻礙該用例。預設值為false。以下示例顯示了伺服器上的區域配置,客戶端包含相應的客戶端[CACHING_]PROXY區域,其中包含對此伺服器區域中鍵的興趣:

<gfe:partitioned-region name="ServerSideRegion" enable-subscription-conflation="true">
  ...
</gfe:partitioned-region>

要控制在客戶端與叢集中的伺服器斷開連線後,“持久”訂閱佇列維護的時間量(以秒為單位),請按如下方式設定<gfe:client-cache>元素上的durable-client-timeout屬性:

<gfe:client-cache durable-client-timeout="600">
  ...
</gfe:client-cache>

關於客戶端興趣工作原理和功能的全面深入討論超出了本文件的範圍。

有關更多詳細資訊,請參閱 Pivotal GemFire 文件中關於客戶端到伺服器事件分發的部分。

5.5.16. JSON 支援

Pivotal GemFire 支援在區域中快取 JSON 文件,並能夠使用 Pivotal GemFire OQL(物件查詢語言)查詢儲存的 JSON 文件。JSON 文件內部以 PdxInstance 型別儲存,使用 JSONFormatter 類執行 JSON 文件(作為 String)的轉換。

Spring Data for Pivotal GemFire 提供了<gfe-data:json-region-autoproxy/>元素,以啟用一個AOP元件來建議適當的代理區域操作,這有效地封裝了JSONFormatter,從而允許您的應用程式直接使用JSON字串。

此外,寫入 JSON 配置區域的 Java 物件將使用 Jackson 的 ObjectMapper 自動轉換為 JSON。當這些值被讀回時,它們將作為 JSON 字串返回。

預設情況下,<gfe-data:json-region-autoproxy/>為所有區域執行轉換。要將此功能應用於選定的區域,請在region-refs屬性中提供逗號分隔的區域 bean ID 列表。其他屬性包括pretty-print標誌(預設為false)和convert-returned-collections

此外,預設情況下,getAll()values()區域操作的結果會針對已配置的區域進行轉換。這是透過在本地記憶體中建立並行資料結構來完成的。這對於大型集合可能會產生顯著的開銷,因此如果您希望停用這些區域操作的自動轉換,請將convert-returned-collections設定為false

某些區域操作(特別是那些使用 Pivotal GemFire 專有 Region.Entry 的操作,例如:entries(boolean)entrySet(boolean)getEntry() 型別)不作為 AOP 建議的目標。此外,entrySet() 方法(返回 Set<java.util.Map.Entry<?, ?>>)也不受影響。

以下示例配置顯示瞭如何設定pretty-printconvert-returned-collections屬性

<gfe-data:json-region-autoproxy region-refs="myJsonRegion" pretty-print="true" convert-returned-collections="false"/>

此功能也與GemfireTemplate操作無縫銜接,前提是模板宣告為Spring bean。目前,不支援原生QueryService操作。

5.6. 配置索引

Pivotal GemFire 允許在區域資料上建立索引(有時也複數為“索引”)以提高 OQL(物件查詢語言)查詢的效能。

在 Spring Data for Pivotal GemFire 中,索引使用 index 元素宣告,如以下示例所示:

<gfe:index id="myIndex" expression="someField" from="/SomeRegion" type="HASH"/>

在 Spring Data for Pivotal GemFire 的 XML 模式(也稱為 SDG XML 名稱空間)中,index bean 宣告不繫結到 Region,這與 Pivotal GemFire 的原生 cache.xml 不同。相反,它們是頂層元素,類似於 <gfe:cache> 元素。這允許您在任何 Region 上宣告任意數量的索引,無論它們是剛剛建立還是已經存在——這相對於 Pivotal GemFire 的原生 cache.xml 格式是一個顯著的改進。

Index必須有一個名稱。您可以使用name屬性為Index指定一個顯式名稱。否則,將使用index bean定義的bean名稱(即id屬性的值)作為Index名稱。

expressionfrom子句構成Index的主要組成部分,用於標識要索引的資料(即from子句中標識的Region)以及用於索引資料的條件(即expression)。expression應基於應用程式域物件欄位,這些欄位用於應用程式定義的OQL查詢的謂詞中,這些查詢用於查詢和查詢儲存在Region中的物件。

考慮以下示例,它有一個lastName屬性:

@Region("Customers")
class Customer {

  @Id
  Long id;

  String lastName;
  String firstName;

  ...
}

現在考慮以下示例,它有一個應用程式定義的SDG Repository來查詢Customer物件

interface CustomerRepository extends GemfireRepository<Customer, Long> {

  Customer findByLastName(String lastName);

  ...
}

SDG Repository finder/query 方法會生成並執行以下 OQL 語句:

SELECT * FROM /Customers c WHERE c.lastName = '$1'

因此,您可能希望建立一個類似於以下內容的Index

<gfe:index id="myIndex" name="CustomersLastNameIndex" expression="lastName" from="/Customers" type="HASH"/>

from子句必須引用一個有效且存在的區域,這是將Index應用於區域的方式。這並非Spring Data for Pivotal GemFire特有。這是Pivotal GemFire的一項功能。

Index type 可以是 Spring Data for Pivotal GemFire 的 IndexType 列舉定義的三個列舉值之一:FUNCTIONALHASHPRIMARY_KEY

每個列舉值對應於實際建立Index(或“定義”——您可以在下一節中找到更多關於“定義”索引的資訊)時呼叫的QueryService create[|Key|Hash]Index方法之一。例如,如果IndexTypePRIMARY_KEY,則呼叫QueryService.createKeyIndex(..)來建立KEY Index

預設值為FUNCTIONAL,並導致呼叫QueryService.createIndex(..)方法之一。有關完整的選項集,請參閱Spring Data for Pivotal GemFire XML模式。

有關 Pivotal GemFire 中索引的更多資訊,請參閱 Pivotal GemFire 使用者指南中的“使用索引”。

5.6.1. 定義索引

除了在Spring容器初始化時,Spring Data for Pivotal GemFire處理Index bean定義時預先建立索引外,您還可以透過使用define屬性在建立索引之前定義所有應用程式索引,如下所示:

<gfe:index id="myDefinedIndex" expression="someField" from="/SomeRegion" define="true"/>

define設定為true(預設為false)時,它實際上不會立即建立Index。所有“定義”的Index都會在Spring ApplicationContext“重新整理”時,或者換句話說,當Spring容器釋出ContextRefreshedEvent時,一次性建立。Spring Data for Pivotal GemFire 將自己註冊為ApplicationListener,監聽ContextRefreshedEvent。當事件觸發時,Spring Data for Pivotal GemFire 呼叫QueryService.createDefinedIndexes()

一次性定義和建立索引可以提高建立索引的速度和效率。

有關更多詳細資訊,請參閱“一次建立多個索引”。

5.6.2. IgnoreIfExistsOverride

Spring Data for Pivotal GemFire Index配置選項中有兩個需要特別提及:ignoreIfExistsoverride

這些選項分別對應於 Spring Data for Pivotal GemFire 的 XML 名稱空間中 <gfe:index> 元素上的 ignore-if-existsoverride 屬性。

在使用這些選項之前,請務必完全理解您正在做什麼。這些選項可能會影響您的應用程式在執行時消耗的效能和資源(例如記憶體)。因此,在 SDG 中,這兩個選項預設都已停用(設定為false)。
這些選項僅在 Spring Data for Pivotal GemFire 中可用,用於解決 Pivotal GemFire 的已知限制。Pivotal GemFire 沒有等效的選項或功能。

每個選項在行為上都有顯著差異,並且完全取決於丟擲的 Pivotal GemFire Index 異常型別。這也意味著,如果沒有丟擲 Pivotal GemFire Index 型別異常,則這兩個選項都不會產生任何影響。這些選項旨在專門處理 Pivotal GemFire IndexExistsExceptionIndexNameConflictException 例項,這些例項可能由於各種(有時是模糊的)原因發生。異常的原因如下:

  • 當存在另一個定義相同但名稱不同的Index時,嘗試建立Index會丟擲IndexExistsException

  • 當存在另一個名稱相同但定義可能不同的Index時,嘗試建立Index會丟擲IndexNameConflictException

Spring Data for Pivotal GemFire 的預設行為始終是快速失敗。因此,預設情況下不會“處理”任何Index Exception。這些Index異常被包裝在SDG GemfireIndexException中並重新丟擲。如果您希望Spring Data for Pivotal GemFire為您處理它們,可以將這些Index bean定義選項之一設定為true

IgnoreIfExists 總是優先於Override,主要是因為它使用的資源更少,僅僅因為它在兩種異常情況下都返回“existing”Index

IgnoreIfExists 行為

當丟擲IndexExistsException並且ignoreIfExists設定為true(或<gfe:index ignore-if-exists="true">)時,本index bean定義或宣告本應建立的Index將簡單地被忽略,並返回現有Index

返回現有Index幾乎沒有影響,因為index bean定義是相同的,這由Pivotal GemFire本身而不是SDG決定。

然而,這也意味著從 Pivotal GemFire 的角度來看(即使用 QueryService.getIndexes()),實際上不存在您的 index bean 定義或宣告中指定的“名稱”的 Index。因此,在使用查詢提示時,您應該小心編寫 OQL 查詢語句,尤其是那些引用被忽略的應用程式 Index 的查詢提示。這些查詢提示需要更改。

當丟擲IndexNameConflictException並且ignoreIfExists設定為true(或<gfe:index ignore-if-exists="true">)時,本index bean定義或宣告本應建立的Index也會被忽略,並再次返回“現有”Index,就像丟擲IndexExistsException時一樣。

但是,當丟擲IndexNameConflictException時,返回現有Index並忽略應用程式對Index的定義風險更大。對於IndexNameConflictException,雖然衝突索引的名稱相同,但定義可能不同。這種情況可能會對應用程式特定的OQL查詢產生影響,您可能會假設索引是專門針對應用程式資料訪問模式和查詢定義的。然而,如果同名索引的定義不同,情況可能並非如此。因此,您應該驗證您的Index名稱。

當被忽略的Index的定義與現有Index的定義顯著不同時,SDG 會盡最大努力通知使用者。但是,為了讓 SDG 完成此操作,它必須能夠找到現有Index,這是透過使用 Pivotal GemFire API(唯一可用的方式)查詢的。
Override 行為

當丟擲IndexExistsException並且override設定為true(或<gfe:index override="true">)時,Index實際上被重新命名。請記住,當存在多個定義相同但名稱不同的索引時,會丟擲IndexExistsExceptions

Spring Data for Pivotal GemFire 只能透過使用 Pivotal GemFire 的 API 來實現這一點,即首先移除現有 Index,然後使用新名稱重新建立 Index。移除或後續建立呼叫都可能失敗。無法原子地執行這兩個操作並在其中任何一個失敗時回滾此聯合操作。

然而,如果成功,那麼您就會遇到與使用ignoreIfExists選項之前相同的問題。任何使用查詢提示引用舊Index名稱的現有OQL查詢語句都必須更改。

當丟擲IndexNameConflictException並且override設定為true(或<gfe:index override="true">)時,現有Index可能會被重新定義。我們之所以說“可能”,是因為在丟擲IndexNameConflictException時,同名且現有Index可能具有完全相同的定義和名稱。

如果是這樣,SDG 會很聰明,即使在override情況下也會按原樣返回現有Index。這種行為沒有害處,因為名稱和定義完全相同。當然,SDG 只有在能夠找到現有Index(這取決於 Pivotal GemFire 的 API)時才能做到這一點。如果找不到,則什麼也不會發生,並丟擲包裝了IndexNameConflictException的 SDG GemfireIndexException

但是,當現有Index的定義不同時,SDG 會嘗試使用index bean定義中指定的Index定義重新建立Index。請確保這是您想要做的,並確保index bean定義符合您的期望和應用程式要求。

IndexNameConflictExceptions 是如何發生的?

IndexExistsExceptions的丟擲可能並不少見,特別是在使用多個配置源配置 Pivotal GemFire 時(Spring Data for Pivotal GemFire、Pivotal GemFire 叢集配置、Pivotal GemFire 原生 cache.xml、API 等)。您應該明確偏愛一種配置方法並堅持使用它。

但是,IndexNameConflictException何時丟擲?

一個特殊情況是在PARTITION區域 (PR) 上定義的Index。當在PARTITION區域(例如X)上定義Index時,Pivotal GemFire 會將Index定義(和名稱)分發到叢集中也託管相同PARTITION區域(即“X”)的其他對等成員。此Index定義到對等成員的分發以及隨後由對等成員建立此Index是按需進行的(即由託管相同 PR 的對等成員),並且是非同步執行的。

在此時間視窗內,Pivotal GemFire 可能無法識別這些待處理的 PR Indexes——例如,透過呼叫 QueryService.getIndexes()QueryService.getIndexes(:Region),甚至 QueryService.getIndex(:Region, indexName:String)

因此,SDG 或其他 Pivotal GemFire 快取客戶端應用程式(不涉及 Spring)唯一確定知道的方法是嘗試建立Index。如果建立失敗並丟擲IndexNameConflictException甚至IndexExistsException,則應用程式就知道存在問題。這是因為QueryService Index 建立會等待待處理的Index定義,而其他 Pivotal GemFire API 呼叫則不會。

無論如何,SDG 都會盡最大努力通知您發生了什麼或正在發生什麼,並告訴您糾正措施。鑑於所有 Pivotal GemFire QueryService.createIndex(..) 方法都是同步阻塞操作,Pivotal GemFire 的狀態在丟擲這些索引型別異常後應該是一致且可訪問的。因此,SDG 可以根據您的配置檢查系統狀態並採取相應行動。

在所有其他情況下,SDG 採用快速失敗策略。

5.7. 配置 DiskStore

Spring Data for Pivotal GemFire 透過disk-store元素支援DiskStore配置和建立,如以下示例所示:

<gfe:disk-store id="Example" auto-compact="true" max-oplog-size="10"
                queue-size="50" time-interval="9999">
    <gfe:disk-dir location="/disk/location/one" max-size="20"/>
    <gfe:disk-dir location="/disk/location/two" max-size="20"/>
</gfe:disk-store>

DiskStore例項用於區域的檔案系統持久備份和逐出條目的溢位,以及WAN閘道器的持久備份。多個Pivotal GemFire元件可以共享同一個DiskStore。此外,一個DiskStore可以定義多個檔案系統目錄,如前面的示例所示。

有關永續性和溢位以及DiskStore例項配置選項的完整解釋,請參閱Pivotal GemFire的文件。

5.8. 配置快照服務

Spring Data for Pivotal GemFire 透過使用Pivotal GemFire 的快照服務來支援快取和區域快照。開箱即用的快照服務支援提供了一些便捷功能,以簡化 Pivotal GemFire 的 快取區域 快照服務 API 的使用。

正如Pivotal GemFire 文件所解釋的,快照允許您儲存並隨後重新載入快取資料,這對於在環境之間移動資料(例如從生產環境到暫存或測試環境)以在受控上下文中重現資料相關問題非常有用。您可以將 Spring Data for Pivotal GemFire 的快照服務支援與Spring 的 bean 定義配置檔案結合使用,以根據需要載入特定於環境的快照資料。

Spring Data for Pivotal GemFire 對 Pivotal GemFire 快照服務的支援始於<gfe-data> XML 名稱空間中的<gfe-data:snapshot-service>元素。

例如,您可以透過使用幾個快照匯入和一個數據匯出定義來定義要載入和儲存的快取範圍快照,如下所示:

<gfe-data:snapshot-service id="gemfireCacheSnapshotService">
  <gfe-data:snapshot-import location="/absolute/filesystem/path/to/import/fileOne.snapshot"/>
  <gfe-data:snapshot-import location="relative/filesystem/path/to/import/fileTwo.snapshot"/>
  <gfe-data:snapshot-export
      location="/absolute/or/relative/filesystem/path/to/export/directory"/>
</gfe-data:snapshot-service>

您可以定義任意數量的匯入和匯出。您可以只定義匯入或只定義匯出。檔案位置和目錄路徑可以是絕對的,也可以是相對於 Spring Data for Pivotal GemFire 應用程式(即 JVM 程序的工作目錄)的。

前面的示例非常簡單,在這種情況下定義的快照服務引用了預設名稱為gemfireCache的Pivotal GemFire快取例項(如配置快取中所述)。如果您將快取bean定義命名為非預設名稱,則可以使用cache-ref屬性按名稱引用快取bean,如下所示:

<gfe:cache id="myCache"/>
...
<gfe-data:snapshot-service id="mySnapshotService" cache-ref="myCache">
  ...
</gfe-data:snapshot-service>

您還可以透過指定region-ref屬性來為特定區域定義快照服務,如下所示:

<gfe:partitioned-region id="Example" persistent="false" .../>
...
<gfe-data:snapshot-service id="gemfireCacheRegionSnapshotService" region-ref="Example">
  <gfe-data:snapshot-import location="relative/path/to/import/example.snapshot/>
  <gfe-data:snapshot-export location="/absolute/path/to/export/example.snapshot/>
</gfe-data:snapshot-service>

當指定region-ref屬性時,Spring Data for Pivotal GemFire的SnapshotServiceFactoryBeanregion-ref屬性值解析為Spring容器中定義的Region bean,並建立一個RegionSnapshotService。快照匯入和匯出定義的運作方式相同。但是,location必須引用匯出上的檔案。

Pivotal GemFire 嚴格要求匯入的快照檔案在被引用之前必須實際存在。對於匯出,Pivotal GemFire 會建立快照檔案。如果匯出的快照檔案已存在,則資料將被覆蓋。
Spring Data for Pivotal GemFire 在<gfe-data:snapshot-service>元素上包含一個suppress-import-on-init屬性,用於禁止配置的快照服務在初始化時嘗試將資料匯入快取或區域。例如,當從一個區域匯出的資料用於另一個區域的匯入時,這非常有用。

5.8.1. 快照位置

對於基於快取的快照服務(即CacheSnapshotService),您通常會傳遞一個包含所有快照檔案的目錄來載入,而不是單個快照檔案,正如CacheSnapshotService API中過載的load方法所示。

當然,您可以使用過載的load(:File[], :SnapshotFormat, :SnapshotOptions)方法來具體指定要載入到 Pivotal GemFire 快取中的快照檔案。

然而,Spring Data for Pivotal GemFire 認識到,典型的開發人員工作流程可能是從一個環境提取資料並匯出到多個快照檔案,將所有這些檔案壓縮,然後方便地將 zip 檔案移動到另一個環境進行匯入。

因此,Spring Data for Pivotal GemFire 允許您在匯入時為基於cache的快照服務指定一個 jar 或 zip 檔案,如下所示:

  <gfe-data:snapshot-service id="cacheBasedSnapshotService" cache-ref="gemfireCache">
    <gfe-data:snapshot-import location="/path/to/snapshots.zip"/>
  </gfe-data:snapshot-service>

Spring Data for Pivotal GemFire 方便地解壓提供的 zip 檔案並將其視為目錄匯入(載入)。

5.8.2. 快照過濾器

定義多個快照匯入和匯出的真正強大之處在於使用快照過濾器。快照過濾器實現了 Pivotal GemFire 的 SnapshotFilter 介面,用於過濾區域條目,以便在匯入時包含到區域中,並在匯出時包含到快照中。

Spring Data for Pivotal GemFire 允許您透過使用filter-ref屬性或匿名巢狀 bean 定義來在匯入和匯出時使用快照過濾器,如以下示例所示:

<gfe:cache/>

<gfe:partitioned-region id="Admins" persistent="false"/>
<gfe:partitioned-region id="Guests" persistent="false"/>

<bean id="activeUsersFilter" class="example.gemfire.snapshot.filter.ActiveUsersFilter/>

<gfe-data:snapshot-service id="adminsSnapshotService" region-ref="Admins">
  <gfe-data:snapshot-import location="/path/to/import/users.snapshot">
    <bean class="example.gemfire.snapshot.filter.AdminsFilter/>
  </gfe-data:snapshot-import>
  <gfe-data:snapshot-export location="/path/to/export/active/admins.snapshot" filter-ref="activeUsersFilter"/>
</gfe-data:snapshot-service>

<gfe-data:snapshot-service id="guestsSnapshotService" region-ref="Guests">
  <gfe-data:snapshot-import location="/path/to/import/users.snapshot">
    <bean class="example.gemfire.snapshot.filter.GuestsFilter/>
  </gfe-data:snapshot-import>
  <gfe-data:snapshot-export location="/path/to/export/active/guests.snapshot" filter-ref="activeUsersFilter"/>
</gfe-data:snapshot-service>

此外,您可以使用ComposableSnapshotFilter類表達更復雜的快照過濾器。該類實現了Pivotal GemFire的SnapshotFilter介面以及複合軟體設計模式。

簡而言之,複合軟體設計模式允許您組合多個相同型別的物件,並將聚合視為該物件型別的單個例項——這是一種強大而有用的抽象。

ComposableSnapshotFilter有兩個工廠方法,andor。它們允許您分別使用 AND 和 OR 邏輯運算子邏輯組合單個快照過濾器。工廠方法接受SnapshotFilters列表。

以下示例顯示了ComposableSnapshotFilter的定義

<bean id="activeUsersSinceFilter" class="org.springframework.data.gemfire.snapshot.filter.ComposableSnapshotFilter"
      factory-method="and">
  <constructor-arg index="0">
    <list>
      <bean class="org.example.app.gemfire.snapshot.filter.ActiveUsersFilter"/>
      <bean class="org.example.app.gemfire.snapshot.filter.UsersSinceFilter"
            p:since="2015-01-01"/>
    </list>
  </constructor-arg>
</bean>

然後,您可以繼續使用oractivesUsersSinceFilter與其他過濾器組合,如下所示:

<bean id="covertOrActiveUsersSinceFilter" class="org.springframework.data.gemfire.snapshot.filter.ComposableSnapshotFilter"
      factory-method="or">
  <constructor-arg index="0">
    <list>
      <ref bean="activeUsersSinceFilter"/>
      <bean class="example.gemfire.snapshot.filter.CovertUsersFilter"/>
    </list>
  </constructor-arg>
</bean>

5.8.3. 快照事件

預設情況下,Spring Data for Pivotal GemFire 在啟動時使用 Pivotal GemFire 的快照服務匯入資料,並在關閉時匯出資料。但是,您可能希望在 Spring 應用程式中觸發定期的、基於事件的快照,用於匯入或匯出。

為此,Spring Data for Pivotal GemFire 定義了兩個額外的 Spring 應用程式事件,分別擴充套件了 Spring 的 ApplicationEvent 類,用於匯入和匯出:ImportSnapshotApplicationEventExportSnapshotApplicationEvent

這兩個應用程式事件可以針對整個 Pivotal GemFire 快取或單個 Pivotal GemFire 區域。這些類中的建構函式接受一個可選的區域路徑名(例如/Example)以及零個或多個SnapshotMetadata例項。

SnapshotMetadata陣列會覆蓋由<gfe-data:snapshot-import><gfe-data:snapshot-export>子元素定義的快照元資料,這些子元素在快照應用程式事件未明確提供SnapshotMetadata的情況下使用。每個獨立的SnapshotMetadata例項都可以定義自己的locationfilters屬性。

Spring ApplicationContext中定義的所有快照服務bean都會接收匯入和匯出快照應用程式事件。但是,只有匹配的快照服務bean才會處理匯入和匯出事件。

如果定義的快照服務bean是RegionSnapshotService並且其區域引用(由region-ref屬性確定)與快照應用程式事件指定的區域路徑名匹配,則基於區域的[Import|Export]SnapshotApplicationEvent匹配。

基於快取的[Import|Export]SnapshotApplicationEvent(即沒有區域路徑名的快照應用程式事件)會觸發所有快照服務 bean(包括任何RegionSnapshotService bean)分別執行匯入或匯出。

您可以使用 Spring 的 ApplicationEventPublisher 介面從應用程式中觸發匯入和匯出快照應用程式事件,如下所示:

@Component
public class ExampleApplicationComponent {

  @Autowired
  private ApplicationEventPublisher eventPublisher;

  @Resource(name = "Example")
  private Region<?, ?> example;

  public void someMethod() {

    ...

    File dataSnapshot = new File(System.getProperty("user.dir"), "/path/to/export/data.snapshot");

    SnapshotFilter myFilter = ...;

    SnapshotMetadata exportSnapshotMetadata =
        new SnapshotMetadata(dataSnapshot, myFilter, null);

    ExportSnapshotApplicationEvent exportSnapshotEvent =
        new ExportSnapshotApplicationEvent(this, example.getFullPath(), exportSnapshotMetadata)

    eventPublisher.publishEvent(exportSnapshotEvent);

    ...
  }
}

在前面的示例中,只有/Example區域的快照服務bean會捕獲並處理匯出事件,將過濾後的“/Example”區域資料儲存到應用程式工作目錄子目錄中的data.snapshot檔案。

使用 Spring 應用程式事件和訊息子系統是保持應用程式鬆散耦合的好方法。您還可以使用 Spring 的排程服務定期觸發快照應用程式事件。

5.9. 配置函式服務

Spring Data for Pivotal GemFire 提供了註解支援,用於實現、註冊和執行 Pivotal GemFire 函式。

Spring Data for Pivotal GemFire 還提供 XML 名稱空間支援,用於註冊 Pivotal GemFire 函式 以進行遠端函式執行。

有關函式執行框架的更多資訊,請參閱 Pivotal GemFire 的文件

Pivotal GemFire 函式被宣告為 Spring bean,並且必須實現org.apache.geode.cache.execute.Function介面或擴充套件org.apache.geode.cache.execute.FunctionAdapter

名稱空間使用熟悉的模式來宣告函式,如以下示例所示:

<gfe:function-service>
  <gfe:function>
      <bean class="example.FunctionOne"/>
      <ref bean="function2"/>
  </gfe:function>
</gfe:function-service>

<bean id="function2" class="example.FunctionTwo"/>

5.10. 配置廣域網閘道器

WAN 閘道器提供了一種跨地理位置同步 Pivotal GemFire 分散式系統的方式。Spring Data for Pivotal GemFire 提供 XML 名稱空間支援,用於配置 WAN 閘道器,如以下示例所示。

5.10.1. Pivotal GemFire 7.0 中的 WAN 配置

在下面的示例中,透過向 Region 新增子元素(gateway-sendergateway-sender-ref)來為PARTITION Region 配置GatewaySendersGatewaySender可以註冊EventFiltersTransportFilters

以下示例還顯示了AsyncEventQueue的示例配置,該配置也必須自動連線到Region(未顯示)

<gfe:partitioned-region id="region-with-inner-gateway-sender" >
    <gfe:gateway-sender remote-distributed-system-id="1">
        <gfe:event-filter>
	        <bean class="org.springframework.data.gemfire.example.SomeEventFilter"/>
        </gfe:event-filter>
        <gfe:transport-filter>
	        <bean class="org.springframework.data.gemfire.example.SomeTransportFilter"/>
        </gfe:transport-filter>
    </gfe:gateway-sender>
    <gfe:gateway-sender-ref bean="gateway-sender"/>
</gfe:partitioned-region>

<gfe:async-event-queue id="async-event-queue" batch-size="10" persistent="true" disk-store-ref="diskstore"
        maximum-queue-memory="50">
    <gfe:async-event-listener>
        <bean class="example.AsyncEventListener"/>
    </gfe:async-event-listener>
</gfe:async-event-queue>

<gfe:gateway-sender id="gateway-sender" remote-distributed-system-id="2">
    <gfe:event-filter>
        <ref bean="event-filter"/>
        <bean class="org.springframework.data.gemfire.example.SomeEventFilter"/>
    </gfe:event-filter>
    <gfe:transport-filter>
        <ref bean="transport-filter"/>
        <bean class="org.springframework.data.gemfire.example.SomeTransportFilter"/>
    </gfe:transport-filter>
</gfe:gateway-sender>

<bean id="event-filter" class="org.springframework.data.gemfire.example.AnotherEventFilter"/>
<bean id="transport-filter" class="org.springframework.data.gemfire.example.AnotherTransportFilter"/>

GatewaySender的另一端是相應的GatewayReceiver,用於接收閘道器事件。GatewayReceiver也可以配置EventFiltersTransportFilters,如下所示:

<gfe:gateway-receiver id="gateway-receiver" start-port="12345" end-port="23456" bind-address="192.168.0.1">
    <gfe:transport-filter>
        <bean class="org.springframework.data.gemfire.example.SomeTransportFilter"/>
    </gfe:transport-filter>
</gfe:gateway-receiver>

有關所有配置選項的詳細說明,請參閱 Pivotal GemFire 文件

6. 使用註解透過Spring容器啟動Pivotal GemFire

Spring Data for Pivotal GemFire (SDG) 2.0 引入了一種新的基於註解的配置模型,用於使用 Spring 容器配置和啟動 Pivotal GemFire。

引入基於註解的方法來在 Spring 上下文中配置 Pivotal GemFire 的主要動機是使 Spring 應用程式開發人員能夠儘可能快速輕鬆開始使用

我們開始吧!

如果您想更快地開始,請參閱快速入門部分。

6.1. 介紹

考慮到所有配置屬性和不同的配置選項,Pivotal GemFire 可能難以正確設定和使用

不同的支援拓撲結構進一步增加了複雜性

基於註解的配置模型旨在簡化所有這些及更多。

基於註解的配置模型是使用 Spring Data for Pivotal GemFire 的 XML 名稱空間進行 XML 配置的替代方案。使用 XML,您可以使用 gfe XML 模式進行配置,並使用 gfe-data XML 模式進行資料訪問。有關更多詳細資訊,請參閱“使用 Spring 容器啟動 Pivotal GemFire”。

截至 SDG 2.0,基於註解的配置模型尚不支援 Pivotal GemFire WAN 元件和拓撲的配置。

與 Spring Boot 類似,Spring Data for Pivotal GemFire 的基於註解的配置模型被設計為一種主觀的、約定優於配置的方法,用於使用 Pivotal GemFire。實際上,這種基於註解的配置模型是受 Spring Boot 以及其他幾個 Spring 和 Spring Data 專案的集體啟發。

遵循約定,所有註解都為所有配置屬性提供合理且明智的預設值。給定註解屬性的預設值直接對應於 Pivotal GemFire 為相同配置屬性提供的預設值。

其目的是讓您透過在 Spring @Configuration@SpringBootApplication 類上宣告適當的註解來啟用 Pivotal GemFire 功能或嵌入式服務,而無需不必要地配置大量屬性即可使用該功能或服務。

再次強調,快速輕鬆上手 是主要目標。

但是,如果您需要,可以自定義 Pivotal GemFire 的配置元資料和行為,Spring Data for Pivotal GemFire 的基於註解的配置會悄然退讓。您只需指定要調整的配置屬性。此外,正如我們將在本文件後面看到的那樣,有多種方法可以透過使用註解來配置 Pivotal GemFire 功能或嵌入式服務。

您可以在 org.springframework.data.gemfire.config.annotation 包中找到所有新的 SDG Java Annotations

6.2. 使用 Spring 配置 Pivotal GemFire 應用程式

與所有透過 @SpringBootApplication 註解應用程式類來啟動的 Spring Boot 應用程式一樣,Spring Boot 應用程式可以透過宣告以下三個主要註解中的任何一個,輕鬆地成為 Pivotal GemFire 快取應用程式

  • @ClientCacheApplication

  • @PeerCacheApplication

  • @CacheServerApplication

這三個註解是 Spring 應用程式開發人員使用 Pivotal GemFire 時的起點。

為了實現這些註解背後的意圖,您必須理解可以使用 Pivotal GemFire 建立兩種型別的快取例項:客戶端快取或對等快取。

您可以將 Spring Boot 應用程式配置為 Pivotal GemFire 快取客戶端,並使用 ClientCache 例項,該例項可以與現有 Pivotal GemFire 伺服器叢集通訊,用於管理應用程式的資料。客戶端-伺服器拓撲是使用 Pivotal GemFire 時最常見的系統架構,您可以透過簡單地使用 @ClientCacheApplication 註解您的 Spring Boot 應用程式,使其成為具有 ClientCache 例項的快取客戶端。

或者,Spring Boot 應用程式可能是 Pivotal GemFire 叢集的對等成員。也就是說,應用程式本身只是管理資料的伺服器叢集中的另一個伺服器。當您使用 @PeerCacheApplication 註解您的應用程式類時,Spring Boot 應用程式會建立一個“嵌入式”對等 Cache 例項。

透過擴充套件,對等快取應用程式也可以充當 CacheServer,允許快取客戶端連線並對伺服器執行資料訪問操作。這可以透過使用 @CacheServerApplication 而不是 @PeerCacheApplication 註解應用程式類來實現,它會建立一個對等 Cache 例項以及允許快取客戶端連線的 CacheServer

Pivotal GemFire 伺服器預設情況下不一定是快取伺服器。也就是說,伺服器不一定僅僅因為它是一個伺服器就被設定為服務快取客戶端。Pivotal GemFire 伺服器可以是管理資料的叢集的對等成員(資料節點),而不服務任何客戶端,而叢集中的其他對等成員除了管理資料之外,確實被設定為服務客戶端。還可以將叢集中的某些對等成員設定為非資料節點,稱為資料訪問器,它們不儲存資料,但作為代理為客戶端提供 CacheServers 服務。Pivotal GemFire 支援許多不同的拓撲和叢集配置,但這些超出了本文件的範圍。

例如,如果您想建立一個 Spring Boot 快取客戶端應用程式,請從以下內容開始

基於 Spring 的 Pivotal GemFire ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication
class ClientApplication { .. }

或者,如果您想建立一個帶有嵌入式對等 Cache 例項的 Spring Boot 應用程式,其中您的應用程式將是 Pivotal GemFire 形成的叢集(分散式系統)的伺服器和對等成員,請從以下內容開始

基於 Spring 的 Pivotal GemFire 嵌入式對等 Cache 應用程式
@SpringBootApplication
@PeerCacheApplication
class ServerApplication { .. }

或者,您可以使用 @CacheServerApplication 註解代替 @PeerCacheApplication 來建立嵌入式對等 Cache 例項以及在 localhost 上執行的 CacheServer,監聽預設快取伺服器埠 40404,如下所示

帶有 CacheServer 的基於 Spring 的 Pivotal GemFire 嵌入式對等 Cache 應用程式
@SpringBootApplication
@CacheServerApplication
class ServerApplication { .. }

6.3. 客戶端/伺服器應用程式詳細資訊

客戶端可以透過多種方式連線並與 Pivotal GemFire 叢集中的伺服器通訊。最常見和推薦的方法是使用 Pivotal GemFire 定位器。

快取客戶端可以連線到 Pivotal GemFire 叢集中的一個或多個定位器,而不是直接連線到 CacheServer。使用定位器而不是直接 CacheServer 連線的優點是,定位器向客戶端提供有關其連線的叢集的元資料。此元資料包括哪些伺服器包含感興趣的資料或哪些伺服器負載最少等資訊。客戶端 Pool 與定位器結合使用,還提供了 CacheServer 崩潰時的故障轉移功能。透過在客戶端 Pool 中啟用 PARTITION 區域 (PR) 單跳功能,客戶端被直接路由到包含客戶端請求和所需資料的伺服器。
定位器也是叢集中的對等成員。定位器實際上構成了 Pivotal GemFire 節點叢集。也就是說,所有由定位器連線的節點都是叢集中的對等體,新成員使用定位器加入叢集並查詢其他成員。

預設情況下,當建立 ClientCache 例項時,Pivotal GemFire 會設定一個連線到在 localhost 上執行並監聽埠 40404CacheServer 的“DEFAULT”PoolCacheServer 監聽埠 40404,接受所有系統 NIC 上的連線。您無需執行任何特殊操作即可使用客戶端-伺服器拓撲。只需使用 @CacheServerApplication 註解您的伺服器端 Spring Boot 應用程式,並使用 @ClientCacheApplication 註解您的客戶端 Spring Boot 應用程式,即可開始使用。

如果您願意,甚至可以使用 Gfsh 的 start server 命令啟動伺服器。您的 Spring Boot @ClientCacheApplication 仍然可以連線到伺服器,無論它是如何啟動的。但是,您可能更喜歡使用 Spring Data for Pivotal GemFire 的方法配置和啟動伺服器,因為正確註解的 Spring Boot 應用程式類更直觀且更易於除錯。

作為應用程式開發人員,您無疑會希望自定義 Pivotal GemFire 設定的“DEFAULT”Pool,以便可能連線到一個或多個定位器,如下例所示

使用定位器的基於 Spring 的 Pivotal GemFire ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication(locators = {
    @Locator(host = "boombox" port = 11235),
    @Locator(host = "skullbox", port = 12480)
})
class ClientApplication { .. }

除了 locators 屬性之外,@ClientCacheApplication 註解還具有 servers 屬性。servers 屬性可用於指定一個或多個巢狀的 @Server 註解,如果需要,允許快取客戶端直接連線到一個或多個伺服器。

您可以使用 locatorsservers 屬性,但不能同時使用兩者(Pivotal GemFire 強制執行此規則)。

您還可以透過使用 @EnablePool@EnablePools 註解來配置額外的 Pool 例項(除了當使用 @ClientCacheApplication 註解建立 ClientCache 例項時 Pivotal GemFire 提供的“DEFAULT”Pool)。

@EnablePools 是一個複合註解,它在單個類上聚合了多個巢狀的 @EnablePool 註解。Java 8 及更早版本不允許在單個類上宣告多個相同型別的註解。

以下示例使用 @EnablePool@EnablePools 註解

使用多個命名 Pools 的基於 Spring 的 Pivotal GemFire ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication(logLevel = "info")
@EnablePool(name = "VenusPool", servers = @Server(host = "venus", port = 48484),
    min-connections = 50, max-connections = 200, ping-internal = 15000,
    prSingleHopEnabled = true, readTimeout = 20000, retryAttempts = 1,
    subscription-enable = true)
@EnablePools(pools = {
    @EnablePool(name = "SaturnPool", locators = @Locator(host="skullbox", port=20668),
        subsription-enabled = true),
    @EnablePool(name = "NeptunePool", severs = {
            @Server(host = "saturn", port = 41414),
            @Server(host = "neptune", port = 42424)
        }, min-connections = 25))
})
class ClientApplication { .. }

name 屬性是 @EnablePool 註解唯一必需的屬性。正如我們稍後將看到的,name 屬性的值對應於在 Spring 容器中建立的 Pool bean 的名稱以及用於引用相應配置屬性的名稱。它也是 Pivotal GemFire 註冊和使用的 Pool 的名稱。

類似地,在伺服器上,您可以配置多個 CacheServers,客戶端可以連線到它們,如下所示

使用多個命名 CacheServers 的基於 Spring 的 Pivotal GemFire CacheServer 應用程式
@SpringBootApplication
@CacheSeverApplication(logLevel = "info", autoStartup = true, maxConnections = 100)
@EnableCacheServer(name = "Venus", autoStartup = true,
    hostnameForClients = "venus", port = 48484)
@EnableCacheServers(servers = {
    @EnableCacheServer(name = "Saturn", hostnameForClients = "saturn", port = 41414),
    @EnableCacheServer(name = "Neptune", hostnameForClients = "neptune", port = 42424)
})
class ServerApplication { .. }
@EnablePools 類似,@EnableCacheServers 是一個複合註解,用於在單個類上聚合多個 @EnableCacheServer 註解。同樣,Java 8 及更早版本不允許在單個類上宣告多個相同型別的註解。

細心的讀者可能已經注意到,在所有情況下,您都為所有主機名、埠和麵向配置的註解屬性指定了硬編碼值。當應用程式被推廣並部署到不同的環境(例如從 DEV 到 QA 到 STAGING 到 PROD)時,這並不理想。

下一節將介紹如何處理在執行時確定的動態配置。

6.4. 配置和啟動定位器

除了 Pivotal GemFire 快取應用程式,您還可以建立 Pivotal GemFire 定位器應用程式。

Pivotal GemFire 定位器是一個 JVM 程序,允許節點作為對等成員加入 Pivotal GemFire 叢集。定位器還使客戶端能夠發現叢集中的伺服器。定位器向客戶端提供元資料,以在叢集成員之間均勻地平衡負載,啟用單跳資料訪問操作,以及其他功能。

關於定位器的完整討論超出了本文件的範圍。建議讀者閱讀 Pivotal GemFire 使用者指南,瞭解有關定位器及其在叢集中作用的更多詳細資訊。

要配置和啟動獨立定位器程序,請執行以下操作

Spring Boot, Pivotal GemFire 定位器應用程式
@SpringBootApplication
@LocatorApplication(port = 12345)
class LocatorApplication { ... }

您可以在叢集中啟動多個定位器。唯一的要求是成員名稱在叢集中必須是唯一的。使用 @LocatorApplication 註解的 name 屬性來相應地命名叢集中的成員定位器。或者,您可以在 Spring Boot 的 application.properties 中設定 spring.data.gemfire.locator.name 屬性。

此外,如果您在同一臺機器上 fork 多個定位器,則必須確保每個定位器都在唯一的埠上啟動。設定 port 註解屬性或 spring.data.gemfire.locator.port 屬性。

然後,您可以在由定位器或定位器加入的叢集中啟動 1 個或多個 Pivotal GemFire 對等快取成員,這些成員也使用 Spring 配置和引導,如下所示

Spring Boot,Pivotal GemFire CacheServer 應用程式,由 localhost 上的定位器,埠 12345 加入
@SpringBootApplication
@CacheServerApplication(locators = "localhost[12345]")
class ServerApplication { ... }

同樣,您可以根據需要啟動任意數量的 ServerApplication 類,它們都由我們上面的定位器加入。您只需確保成員名稱唯一即可。

@LocatorApplication 用於配置和啟動獨立的 Pivotal GemFire Locator 應用程式程序。此程序只能是 Locator,不能是其他任何東西。如果您嘗試使用快取例項啟動 Locator,SDG 將丟擲錯誤。

如果您想同時啟動一個快取例項和一個嵌入式定位器,那麼您應該使用 @EnableLocator 註解。

在開發過程中啟動嵌入式定位器很方便。但是,強烈建議您在生產環境中執行獨立的定位器程序以實現高可用性。如果叢集中所有定位器都宕機,那麼叢集將保持完整,但是,無法加入新成員,這對於線性橫向擴充套件以滿足需求非常重要。

有關更多詳細資訊,請參閱“配置嵌入式定位器”一節。

6.5. 使用 Configurers 進行執行時配置

設計基於註解的配置模型的另一個目標是保留註解屬性中的型別安全。例如,如果配置屬性可以表示為 int(例如埠號),那麼該屬性的型別應該是 int

不幸的是,這不利於執行時動態和可解析的配置。

Spring 的一個更精細的特性是能夠在 Spring 容器中配置 bean 時,在配置元資料的屬性或屬性中使用屬性佔位符和 SpEL 表示式。但是,這將要求所有註解屬性都是 String 型別,從而放棄了型別安全,這是不可取的。

因此,Spring Data for Pivotal GemFire 借鑑了 Spring 中另一個常用模式,即 Configurers。Spring Web MVC 中提供了許多不同的 Configurer 介面,包括 org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer

Configurers 設計模式使應用程式開發人員能夠在啟動時收到回撥,以自定義元件或 bean 的配置。框架回呼叫戶提供的程式碼以在執行時調整配置。此模式的更常見用途之一是根據應用程式的執行時環境提供條件配置。

Spring Data for Pivotal GemFire 提供了多個 Configurer 回撥介面,用於在執行時,在 Spring 管理的由註解建立的 bean 初始化之前,自定義基於註解的配置元資料的不同方面

  • CacheServerConfigurer

  • ClientCacheConfigurer

  • ContinuousQueryListenerContainerConfigurer

  • DiskStoreConfigurer

  • IndexConfigurer

  • PeerCacheConfigurer

  • PoolConfigurer

  • RegionConfigurer

  • GatewayReceiverConfigurer

  • GatewaySenderConfigurer

例如,您可以使用 CacheServerConfigurerClientCacheConfigurer 分別自定義您的 Spring Boot CacheServerClientCache 應用程式使用的埠號。

考慮以下伺服器應用程式示例

使用 CacheServerConfigurer 自定義 Spring Boot CacheServer 應用程式
@SpringBootApplication
@CacheServerApplication(name = "SpringServerApplication")
class ServerApplication {

  @Bean
  CacheServerConfigurer cacheServerPortConfigurer(
          @Value("${gemfire.cache.server.host:localhost}") String cacheServerHost
          @Value("${gemfire.cache.server.port:40404}") int cacheServerPort) {

      return (beanName, cacheServerFactoryBean) -> {
          cacheServerFactoryBean.setBindAddress(cacheServerHost);
          cacheServerFactoryBean.setHostnameForClients(cacheServerHost);
          cacheServerFactoryBean.setPort(cacheServerPort);
      };
  }
}

接下來,考慮以下客戶端應用程式示例

使用 ClientCacheConfigurer 自定義 Spring Boot ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication
class ClientApplication {

  @Bean
  ClientCacheConfigurer clientCachePoolPortConfigurer(
          @Value("${gemfire.cache.server.host:localhost}") String cacheServerHost
          @Value("${gemfire.cache.server.port:40404}") int cacheServerPort) {

      return (beanName, clientCacheFactoryBean) ->
          clientCacheFactoryBean.setServers(Collections.singletonList(
              new ConnectionEndpoint(cacheServerHost, cacheServerPort)));
  }
}

透過使用提供的 Configurers,您可以在啟動期間接收回調,以進一步自定義由相關注解在執行時啟用的配置。

此外,當 Configurer 在 Spring 容器中宣告為 bean 時,bean 定義可以利用其他 Spring 容器特性,例如屬性佔位符、透過在工廠方法引數上使用 @Value 註解的 SpEL 表示式等。

Spring Data for Pivotal GemFire 提供的所有 Configurer 在回撥中都會接收兩部分資訊:由註解在 Spring 容器中建立的 bean 的名稱,以及註解用於建立和配置 Pivotal GemFire 元件的 FactoryBean 的引用(例如,ClientCache 例項由 ClientCacheFactoryBean 建立和配置)。

SDG FactoryBeans 是 SDG 公共 API 的一部分,如果您沒有提供這種新的基於註解的配置模型,您將在 Spring 的基於 Java 的容器配置中使用它們。事實上,註解本身也在使用這些相同的 FactoryBeans 進行配置。因此,本質上,註解是一個外觀,提供了一個額外的抽象層,以方便使用。

鑑於 Configurer 可以像任何其他 POJO 一樣宣告為常規 bean 定義,您可以結合不同的 Spring 配置選項,例如將 Spring Profiles 與使用屬性佔位符和 SpEL 表示式的 Conditions 結合使用。這些和其他巧妙的功能讓您可以建立更復雜和靈活的配置。

但是,Configurers 並不是唯一的選擇。

6.6. 使用 Properties 進行執行時配置

除了 Configurers,基於註解的配置模型中的每個註解屬性都關聯一個相應的配置屬性(字首為 spring.data.gemfire.),該屬性可以在 Spring Boot 的 application.properties 檔案中宣告。

在前述示例的基礎上,客戶端的 application.properties 檔案將定義以下屬性集

客戶端 application.properties
spring.data.gemfire.cache.log-level=info
spring.data.gemfire.pool.Venus.servers=venus[48484]
spring.data.gemfire.pool.Venus.max-connections=200
spring.data.gemfire.pool.Venus.min-connections=50
spring.data.gemfire.pool.Venus.ping-interval=15000
spring.data.gemfire.pool.Venus.pr-single-hop-enabled=true
spring.data.gemfire.pool.Venus.read-timeout=20000
spring.data.gemfire.pool.Venus.subscription-enabled=true
spring.data.gemfire.pool.Saturn.locators=skullbox[20668]
spring.data.gemfire.pool.Saturn.subscription-enabled=true
spring.data.gemfire.pool.Neptune.servers=saturn[41414],neptune[42424]
spring.data.gemfire.pool.Neptune.min-connections=25

相應的伺服器的 application.properties 檔案將定義以下屬性

伺服器 application.properties
spring.data.gemfire.cache.log-level=info
spring.data.gemfire.cache.server.port=40404
spring.data.gemfire.cache.server.Venus.port=43434
spring.data.gemfire.cache.server.Saturn.port=41414
spring.data.gemfire.cache.server.Neptune.port=41414

然後您可以將 @ClientCacheApplication 類簡化為以下內容

Spring @ClientCacheApplication
@SpringBootApplication
@ClientCacheApplication
@EnablePools(pools = {
    @EnablePool(name = "Venus"),
    @EnablePool(name = "Saturn"),
    @EnablePool(name = "Neptune")
})
class ClientApplication { .. }

此外,@CacheServerApplication 類變為以下內容

Spring @CacheServerApplication
@SpringBootApplication
@CacheServerApplication(name = "SpringServerApplication")
@EnableCacheServers(servers = {
    @EnableCacheServer(name = "Venus"),
    @EnableCacheServer(name = "Saturn"),
    @EnableCacheServer(name = "Neptune")
})
class ServerApplication { .. }

前面的示例說明了為什麼“命名”基於註解的 bean 很重要(除了在某些情況下是必需的)。這樣做可以從 XML、屬性和 Java 中引用 Spring 容器中的 bean。甚至可以將註解定義的 bean 注入到應用程式類中,無論出於何種目的,如下例所示

@Component
class MyApplicationComponent {

  @Resource(name = "Saturn")
  CacheServer saturnCacheServer;

  ...
}

同樣,命名一個註解定義的 bean 允許您編寫一個 Configurer 來自定義一個特定的“命名”bean,因為 beanName 是傳遞給回撥的兩個引數之一。

通常,關聯的註解屬性屬性有兩種形式:“命名”屬性和“未命名”屬性。

以下示例展示了這種安排

spring.data.gemfire.cache.server.bind-address=10.105.20.1
spring.data.gemfire.cache.server.Venus.bind-address=10.105.20.2
spring.data.gemfire.cache.server.Saturn...
spring.data.gemfire.cache.server.Neptune...

雖然上面有三個命名的 CacheServers,但也有一個未命名的 CacheServer 屬性,它為任何未指定的屬性值提供預設值,即使對於“命名”的 CacheServers 也是如此。因此,雖然“Venus”設定並覆蓋了自己的 bind-address,但“Saturn”和“Neptune”繼承了“未命名”的 spring.data.gemfire.cache.server.bind-address 屬性。

請參閱註解的 Javadoc,瞭解哪些註解屬性支援基於屬性的配置,以及它們是否支援“命名”屬性而不是預設的“未命名”屬性。

6.6.1. Properties 中的 Properties

按照 Spring 的慣例,您甚至可以用其他 Properties 來表達 Properties,無論是透過以下示例展示瞭如何在 application.properties 檔案中設定巢狀屬性

屬性中的屬性
spring.data.gemfire.cache.server.port=${gemfire.cache.server.port:40404}

以下示例展示瞭如何在 Java 中設定巢狀屬性

屬性佔位符巢狀
@Bean
CacheServerConfigurer cacheServerPortConfigurer(
    @Value("${gemfire.cache.server.port:${some.other.property:40404}}")
    int cacheServerPort) {
  ...
}
屬性佔位符巢狀可以任意深入。

6.7. 配置嵌入式服務

Pivotal GemFire 提供了根據用例啟動應用程式所需的許多不同嵌入式服務的能力。

6.7.1. 配置嵌入式定位器

如前所述,Pivotal GemFire 定位器被客戶端用於連線和查詢叢集中的伺服器。此外,加入現有叢集的新成員使用定位器來查詢其對等體。

對於應用程式開發人員來說,在開發 Spring Boot 和 Spring Data for Pivotal GemFire 應用程式時,啟動一個由兩三個 Pivotal GemFire 伺服器組成的小型叢集通常很方便。您無需啟動單獨的定位器程序,而是可以使用 @EnableLocator 註解您的 Spring Boot @CacheServerApplication 類,如下所示

Spring, 執行嵌入式定位器的 Pivotal GemFire CacheServer 應用程式
@SpringBootApplication
@CacheServerApplication
@EnableLocator
class ServerApplication { .. }

@EnableLocator 註解在運行於 localhost 並監聽預設 Locator 埠 10334 的 Spring Pivotal GemFire CacheServer 應用程式中啟動一個嵌入式 Locator。您可以透過使用相應的註解屬性自定義嵌入式 Locator 繫結的 host(繫結地址)和 port

或者,您可以透過在 application.properties 中設定相應的 spring.data.gemfire.locator.hostspring.data.gemfire.locator.port 屬性來設定 @EnableLocator 屬性。

然後,您可以透過以下方式連線到此定位器,啟動其他支援 Spring Boot @CacheServerApplication 的應用程式

Spring, 連線到定位器的 Pivotal GemFire CacheServer 應用程式
@SpringBootApplication
@CacheServerApplication(locators = "localhost[10334]")
class ServerApplication { .. }

您甚至可以將前面顯示的兩個應用程式類合併到一個類中,並使用您的 IDE 建立不同的執行配置檔案配置,透過使用 Java 系統屬性啟動相同類的不同例項,並進行稍微修改的配置,如下所示

執行嵌入式定位器並連線到定位器的 Spring CacheServer 應用程式
@SpringBootApplication
@CacheServerApplication(locators = "localhost[10334]")
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class);
  }

  @EnableLocator
  @Profile("embedded-locator")
  static class Configuration { }

}

然後,對於每個執行配置檔案,您可以設定和更改以下系統屬性

IDE 執行配置檔案配置
spring.data.gemfire.name=SpringCacheServerOne
spring.data.gemfire.cache.server.port=41414
spring.profiles.active=embedded-locator

ServerApplication 類的執行配置檔案中只有 1 個應設定 -Dspring.profiles.active=embedded-locator Java 系統屬性。然後,您可以更改其他執行配置檔案的 ..name..cache.server.port,並在本地系統上執行一個由 Pivotal GemFire 伺服器組成的小型叢集(分散式系統)。

@EnableLocator 註解僅用於開發時註解,而不是應用程式開發人員在生產環境中使用。我們強烈建議將定位器作為獨立的程序在叢集中執行,以實現高可用性。

有關 Pivotal GemFire Locator 如何工作的更多詳細資訊,請參見此處

6.7.2. 配置嵌入式管理器

Pivotal GemFire Manager 是叢集中的另一個對等成員或節點,負責叢集“管理”。管理包括建立 RegionsIndexesDiskStores 等,以及監控叢集元件的執行時操作和行為。

管理器允許啟用 JMX 的客戶端(例如 Gfsh shell 工具)連線到管理器以管理叢集。也可以使用 JDK 提供的工具(如 JConsole 或 JVisualVM)連線到管理器,因為它們也是啟用 JMX 的客戶端。

也許您也希望將前面顯示的 Spring @CacheServerApplication 也啟用為 Manager。為此,請使用 @EnableManager 註解您的 Spring @Configuration@SpringBootApplication 類。

預設情況下,Manager 繫結到 localhost,監聽預設的 Manager 埠 1099。Manager 的幾個方面可以透過註解屬性或相應的屬性進行配置。

以下示例展示瞭如何在 Java 中建立嵌入式管理器

執行嵌入式管理器的 Spring CacheServer 應用程式
@SpringBootApplication
@CacheServerApplication(locators = "localhost[10334]")
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class);
  }

  @EnableLocator
  @EnableManager
  @Profile("embedded-locator-manager")
  static class Configuration { }

}

使用上述類,您甚至可以使用 Gfsh 連線到小型叢集並對其進行管理,如下所示

$ gfsh
    _________________________     __
   / _____/ ______/ ______/ /____/ /
  / /  __/ /___  /_____  / _____  /
 / /__/ / ____/  _____/ / /    / /
/______/_/      /______/_/    /_/    1.2.1

Monitor and Manage {data-store-name}

gfsh>connect
Connecting to Locator at [host=localhost, port=10334] ..
Connecting to Manager at [host=10.99.199.5, port=1099] ..
Successfully connected to: [host=10.99.199.5, port=1099]

gfsh>list members
         Name          | Id
---------------------- | ----------------------------------------------------
SpringCacheServerOne   | 10.99.199.5(SpringCacheServerOne:14842)<ec><v0>:1024
SpringCacheServerTwo   | 10.99.199.5(SpringCacheServerTwo:14844)<v1>:1025
SpringCacheServerThree | 10.99.199.5(SpringCacheServerThree:14846)<v2>:1026

因為我們還啟用了嵌入式 Locator,所以我們可以透過 Locator 間接連線到 Manager。Locator 允許 JMX 客戶端連線並找到叢集中的 Manager。如果不存在,Locator 會承擔 Manager 的角色。但是,如果不存在 Locator,我們將需要透過以下方式直接連線到 Manager

Gfsh connect 命令直接連線到管理器
gfsh>connect --jmx-manager=localhost[1099]
@EnableLocator 註解類似,@EnableManager 註解也僅用於開發時註解,而不是應用程式開發人員在生產環境中使用。我們強烈建議 Manager,像 Locator 一樣,作為獨立的、獨立的和專用程序在叢集中執行。

有關 Pivotal GemFire 管理和監控的更多詳細資訊,請參見此處

6.7.3. 配置嵌入式 HTTP 伺服器

Pivotal GemFire 也能夠執行嵌入式 HTTP 伺服器。當前的實現由 Eclipse Jetty 支援。

嵌入式 HTTP 伺服器用於託管 Pivotal GemFire 的管理 (Admin) REST API (非公開宣傳的 API)、開發者 REST APIPulse 監控 Web 應用程式

但是,要使用任何這些 Pivotal GemFire 提供的 Web 應用程式,您的系統必須安裝完整的 Pivotal GemFire,並且必須將 GEODE_HOME 環境變數設定為您的安裝目錄。

要啟用嵌入式 HTTP 伺服器,請將 @EnableHttpService 註解新增到任何 @PeerCacheApplication@CacheServerApplication 註解類中,如下所示

執行嵌入式 HTTP 伺服器的 Spring CacheServer 應用程式
@SpringBootApplication
@CacheServerApplication
@EnableHttpService
public class ServerApplication { .. }

預設情況下,嵌入式 HTTP 伺服器監聽埠 7070 以處理 HTTP 客戶端請求。當然,您可以根據需要使用註解屬性或相應的配置屬性來調整埠。

有關 HTTP 支援和所提供服務的更多詳細資訊,請參閱前面的連結。

6.7.4. 配置嵌入式 Memcached 伺服器(Gemcached)

Pivotal GemFire 還實現了 Memcached 協議,能夠為 Memcached 客戶端提供服務。也就是說,Memcached 客戶端可以連線到 Pivotal GemFire 叢集並執行 Memcached 操作,就好像叢集中的 Pivotal GemFire 伺服器是真正的 Memcached 伺服器一樣。

要啟用嵌入式 Memcached 服務,請將 @EnableMemcachedServer 註解新增到任何 @PeerCacheApplication@CacheServerApplication 註解類中,如下所示

執行嵌入式 Memcached 伺服器的 Spring CacheServer 應用程式
@SpringBootApplication
@CacheServerApplication
@EnabledMemcachedServer
public class ServerApplication { .. }

有關 Pivotal GemFire 的 Memcached 服務(稱為“Gemcached”)的更多詳細資訊,請參見此處

6.7.5. 配置嵌入式 Redis 伺服器

Pivotal GemFire 還實現了 Redis 伺服器協議,該協議使 Redis 客戶端能夠連線並與 Pivotal GemFire 伺服器叢集通訊以發出 Redis 命令。截至本文撰寫之時,Pivotal GemFire 中的 Redis 伺服器協議支援仍處於實驗階段。

要啟用嵌入式 Redis 服務,請將 @EnableRedisServer 註解新增到任何 @PeerCacheApplication@CacheServerApplication 註解類中,如下所示

執行嵌入式 Redis 伺服器的 Spring CacheServer 應用程式
@SpringBootApplication
@CacheServerApplication
@EnableRedisServer
public class ServerApplication { .. }
您必須在 Spring [Boot] 應用程式的類路徑中明確宣告 org.apache.geode:geode-redis 模組。

有關 Pivotal GemFire 的 Redis 介面卡的更多詳細資訊,請參見此處

6.8. 配置日誌

通常,需要開啟日誌記錄以準確瞭解 Pivotal GemFire 正在做什麼以及何時進行。

要啟用日誌記錄,請使用 @EnableLogging 註解您的應用程式類,並設定適當的屬性或關聯屬性,如下所示

已啟用日誌記錄的 Spring ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication
@EnableLogging(logLevel="info", logFile="/absolute/file/system/path/to/application.log)
public class ClientApplication { .. }

雖然 logLevel 屬性可以與所有基於快取的應用程式註解一起指定(例如,@ClientCacheApplication(logLevel="info")),但使用 @EnableLogging 註解自定義日誌行為更容易。

此外,您可以透過在 application.properties 中設定 spring.data.gemfire.logging.level 屬性來配置 log-level

有關更多詳細資訊,請參閱 @EnableLogging 註解 Javadoc

6.9. 配置統計資訊

為了更深入地瞭解 Pivotal GemFire 的執行時情況,您可以啟用統計資訊。收集統計資料有助於在發生複雜問題時進行系統分析和故障排除,這些問題通常具有分散式特性,並且時間是一個關鍵因素。

啟用統計資訊後,您可以使用 Pivotal GemFire 的 VSD (Visual Statistics Display) 工具來分析收集到的統計資料。

要啟用統計資訊,請使用 @EnableStatistics 註解您的應用程式類,如下所示

已啟用統計資訊的 Spring ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication
@EnableStatistics
public class ClientApplication { .. }

在伺服器上啟用統計資訊在評估效能時特別有價值。為此,請使用 @EnableStatistics 註解您的 @PeerCacheApplication@CacheServerApplication 類。

您可以使用 @EnableStatistics 註解屬性或相關屬性來自定義統計資料收集過程。

有關更多詳細資訊,請參閱 @EnableStatistics 註解 Javadoc

有關 Pivotal GemFire 統計資訊的更多詳細資訊,請參見此處

6.10. 配置 PDX

Pivotal GemFire 最強大的功能之一是 PDX 序列化。雖然 PDX 的完整討論超出了本文件的範圍,但使用 PDX 進行序列化是 Java 序列化的更好替代方案,具有以下優點

  • PDX 使用集中式型別登錄檔,使物件的序列化位元組更加緊湊。

  • PDX 是一種中立的序列化格式,允許 Java 和 Native 客戶端對相同的資料集進行操作。

  • PDX 支援版本控制,允許新增或刪除物件欄位,而不會影響使用更改後的 PDX 序列化物件的舊版本或新版本的現有應用程式,且不會丟失資料。

  • PDX 允許在 OQL 查詢投影和謂詞中單獨訪問物件欄位,而無需先反序列化物件。

通常,Pivotal GemFire 中需要序列化,無論何時資料在客戶端和伺服器之間或叢集中的對等體之間在正常分發和複製過程中傳輸,以及當資料溢位或持久化到磁碟時。

啟用 PDX 序列化比修改所有應用程式域物件型別以實現 java.io.Serializable 簡單得多,尤其是在不希望對應用程式域模型施加此類限制,或者無法控制正在序列化的物件時,在使用第三方庫(例如,考慮帶有 Coordinate 型別的地理空間 API)時尤其如此。

要啟用 PDX,請使用 @EnablePdx 註解您的應用程式類,如下所示

已啟用 PDX 的 Spring ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication
@EnablePdx
public class ClientApplication { .. }

通常,應用程式的域物件型別要麼實現 org.apache.geode.pdx.PdxSerializable 介面,要麼您可以實現並註冊 org.apache.geode.pdx.PdxSerializer 介面的非侵入式實現來處理所有需要序列化的應用程式域物件型別。

不幸的是,Pivotal GemFire 只允許註冊一個 PdxSerializer,這意味著所有應用程式域物件型別都需要由單個 PdxSerializer 例項處理。然而,這是一個嚴重的反模式和不可維護的做法。

儘管 Pivotal GemFire 只能註冊單個 PdxSerializer 例項,但為每個應用程式域物件型別建立一個 PdxSerializer 實現是合理的。

透過使用組合軟體設計模式,您可以提供一個 PdxSerializer 介面的實現,該實現聚合了所有特定於應用程式域物件型別的 PdxSerializer 例項,但作為一個單一的 PdxSerializer 例項並註冊它。

您可以在 Spring 容器中將此組合 PdxSerializer 宣告為託管 bean,並使用 @EnablePdx 註解中的 serializerBeanName 屬性透過其 bean 名稱引用此組合 PdxSerializer。Spring Data for Pivotal GemFire 會為您處理向 Pivotal GemFire 註冊它的事宜。

以下示例展示瞭如何建立自定義組合 PdxSerializer

啟用 PDX 並使用自定義複合 PdxSerializer 的 Spring ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication
@EnablePdx(serializerBeanName = "compositePdxSerializer")
public class ClientApplication {

  @Bean
  PdxSerializer compositePdxSerializer() {
      return new CompositePdxSerializerBuilder()...
  }
}

也可以將 Pivotal GemFire 的 org.apache.geode.pdx.ReflectionBasedAutoSerializer 宣告為 Spring 上下文中的 bean 定義。

或者,您應該使用 Spring Data for Pivotal GemFire 更強大的 org.springframework.data.gemfire.mapping.MappingPdxSerializer,它使用 Spring Data 對映元資料和基礎設施應用於序列化過程,以實現比單獨反射更高效的處理。

PDX 的許多其他方面和功能可以透過 @EnablePdx 註解屬性或關聯的配置屬性進行調整。

有關更多詳細資訊,請參閱 @EnablePdx 註解 Javadoc

6.11. 配置 Pivotal GemFire 屬性

雖然許多 gemfire.properties 已方便地封裝並在 SDG 基於註解的配置模型中透過註解進行抽象,但不太常用的 Pivotal GemFire 屬性仍然可以透過 @EnableGemFireProperties 註解訪問。

使用 @EnableGemFireProperties 註解您的應用程式類很方便,是建立 gemfire.properties 檔案或在啟動應用程式時在命令列上將 Pivotal GemFire 屬性設定為 Java 系統屬性的不錯替代方案。

我們建議在將應用程式部署到生產環境時,將這些 Pivotal GemFire 屬性設定在 gemfire.properties 檔案中。但是,在開發階段,為了原型設計、除錯和測試目的,單獨設定這些屬性可能會很方便。

一些不常用的 Pivotal GemFire 屬性示例,您通常不需要擔心,包括但不限於:ack-wait-thresholddisable-tcpsocket-buffer-size 等。

要單獨設定任何 Pivotal GemFire 屬性,請使用 @EnableGemFireProperties 註解您的應用程式類,並使用相應屬性設定您希望更改的 Pivotal GemFire 屬性(與 Pivotal GemFire 設定的預設值不同),如下所示

已設定特定 Pivotal GemFire 屬性的 Spring ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication
@EnableGemFireProperties(conflateEvents = true, socketBufferSize = 16384)
public class ClientApplication { .. }

請記住,一些 Pivotal GemFire 屬性是客戶端特定的(例如 conflateEvents),而另一些是伺服器特定的(例如 distributedSystemIdenableNetworkPartitionDetectionenforceUniqueHostmemberTimeoutredundancyZone 等)。

有關 Pivotal GemFire 屬性的更多詳細資訊,請參見此處

6.12. 配置區域

到目前為止,除了 PDX 之外,我們的討論都集中在配置 Pivotal GemFire 的更多管理功能上:建立快取例項、啟動嵌入式服務、啟用日誌和統計、配置 PDX,以及使用 gemfire.properties 來影響低階配置和行為。雖然所有這些配置選項都很重要,但它們都與您的應用程式沒有直接關係。換句話說,我們仍然需要一個地方來儲存應用程式資料並使其普遍可用和可訪問。

Pivotal GemFire 將快取中的資料組織成區域(Regions)。您可以將區域視為關係資料庫中的一個表。通常,一個區域應該只儲存單一型別的物件,這更有利於構建有效的索引和編寫查詢。我們稍後會介紹索引

以前,Spring Data for Pivotal GemFire 使用者需要透過編寫非常詳細的 Spring 配置元資料來顯式定義和宣告應用程式用於儲存資料的區域,無論是使用 SDG API 中的 FactoryBeans 結合 Spring 的基於 Java 的容器配置還是使用XML

以下示例演示瞭如何在 Java 中配置區域 bean

使用 Spring 基於 Java 的容器配置的區域 bean 定義示例
@Configuration
class GemFireConfiguration {

  @Bean("Example")
  PartitionedRegionFactoryBean exampleRegion(GemFireCache gemfireCache) {

      PartitionedRegionFactoryBean<Long, Example> exampleRegion =
          new PartitionedRegionFactoryBean<>();

      exampleRegion.setCache(gemfireCache);
      exampleRegion.setClose(false);
      exampleRegion.setPersistent(true);

      return exampleRegion;
  }

  ...
}

以下示例演示瞭如何在 XML 中配置相同的區域 bean

使用 SDG XML 名稱空間的區域 bean 定義示例
<gfe:partitioned-region id="exampleRegion" name="Example" persistent="true">
    ...
</gfe:partitioned-region>

雖然 Java 或 XML 配置都不算太難指定,但兩者都可能很麻煩,特別是當應用程式需要大量區域時。許多基於關係資料庫的應用程式可能有數百甚至數千個表。

手動定義和宣告所有這些區域將是繁瑣且容易出錯的。現在,有更好的方法。

現在,您可以根據應用程式域物件(實體)本身來定義和配置區域。除非您需要更精細的控制,否則不再需要顯式定義 Spring 配置元資料中的 Region bean 定義。

為了簡化區域建立,Spring Data for Pivotal GemFire 將 Spring Data Repositories 的使用與基於註解的配置的表達能力結合起來,使用新的 @EnableEntityDefinedRegions 註解。

大多數 Spring Data 應用程式開發人員應該已經熟悉Spring Data Repository 抽象和 Spring Data for Pivotal GemFire 的實現/擴充套件,該實現/擴充套件已專門定製以最佳化 Pivotal GemFire 的資料訪問操作。

首先,應用程式開發人員透過定義應用程式的域物件(實體)開始,如下所示

建模書籍的應用程式域物件型別
@Region("Books")
class Book {

  @Id
  private ISBN isbn;

  private Author author;

  private Category category;

  private LocalDate releaseDate;

  private Publisher publisher;

  private String title;

}

接下來,您透過擴充套件 Spring Data Commons org.springframework.data.repository.CrudRepository 介面來定義 Books 的基本儲存庫,如下所示

書籍儲存庫
interface BookRepository extends CrudRepository<Book, ISBN> { .. }

org.springframe.data.repository.CrudRepository 是一個數據訪問物件 (DAO),它提供基本資料訪問操作 (CRUD) 以及對簡單查詢的支援(例如 findById(..))。您可以透過在儲存庫介面上宣告查詢方法來定義其他更復雜的查詢(例如,List<BooK> findByAuthor(Author author);)。

在底層,當 Spring 容器啟動時,Spring Data for Pivotal GemFire 會提供應用程式儲存庫介面的實現。只要您遵循約定,SDG 甚至會實現您定義的查詢方法。

現在,當您定義 Book 類時,您還透過在實體型別上宣告 Spring Data for Pivotal GemFire 對映註解 @Region 來指定 Book 例項對映(儲存)的區域。當然,如果儲存庫介面的型別引數中引用的實體型別(本例中為 Book)沒有用 @Region 註解,則名稱將從實體型別的簡單類名(本例中也為 Book)派生。

Spring Data for Pivotal GemFire 使用對映上下文,該上下文包含應用程式中定義的所有實體的對映元資料,以確定執行時所需的所有區域。

要啟用和使用此功能,請使用 @EnableEntityDefinedRegions 註解應用程式類,如下所示

實體定義的區域配置
@SpringBootApplication
@ClientCacheApplication
@EnableEntityDefinedRegions(basePackages = "example.app.domain")
@EnableGemfireRepositories(basePackages = "example.app.repo")
class ClientApplication { .. }
當在應用程式中使用 Spring Data Repositories 時,從實體類建立區域是最有用的。Spring Data for Pivotal GemFire 的 Repository 支援透過 @EnableGemfireRepositories 註解啟用,如前一個示例所示。
目前,只有明確使用 @Region 註解的實體類才會被掃描到並建立區域。如果實體類未明確對映 @Region,則不會建立區域。

預設情況下,@EnableEntityDefinedRegions 註解遞迴掃描實體類,從宣告 @EnableEntityDefinedRegions 註解的配置類包開始。

但是,通常透過使用包含應用程式實體類的包名設定 basePackages 屬性來限制掃描期間的搜尋。

或者,您可以使用更型別安全的 basePackageClasses 屬性來指定要掃描的包,方法是將該屬性設定為包中包含實體類的實體型別,或者使用專門為識別要掃描的包而建立的非實體佔位符類。

以下示例展示瞭如何指定要掃描的實體型別

使用實體類型別的實體定義區域配置
@SpringBootApplication
@ClientCacheApplication
@EnableGemfireRepositories
@EnableEntityDefinedRegions(basePackageClasses = {
    example.app.books.domain.Book.class,
    example.app.customers.domain.Customer.class
})
class ClientApplication { .. }

除了指定掃描的起始位置外,像 Spring 的 @ComponentScan 註解一樣,您還可以指定 includeexclude 過濾器,其語義與 org.springframework.context.annotation.ComponentScan.Filter 註解完全相同。

有關更多詳細資訊,請參閱 @EnableEntityDefinedRegions 註解 Javadoc

6.12.1. 配置特定型別區域

Pivotal GemFire 支援許多不同型別的區域。每種型別都對應於區域的DataPolicy,它決定了區域中的資料將如何管理(即分散式、複製等)。

其他配置設定(例如區域的 scope)也會影響資料管理方式。有關更多詳細資訊,請參閱 Pivotal GemFire 使用者指南中的“儲存和分發選項”

當您使用通用 @Region 對映註解註釋您的應用程式域物件型別時,Spring Data for Pivotal GemFire 會決定建立哪種型別的區域。SDG 的預設策略在確定要建立的區域型別時會考慮快取型別。

例如,如果您使用 @ClientCacheApplication 註解將應用程式宣告為 ClientCache,SDG 預設會建立一個客戶端 PROXY Region。或者,如果您使用 @PeerCacheApplication@CacheServerApplication 註解將應用程式宣告為對等 Cache,SDG 預設會建立一個伺服器 PARTITION Region

當然,在必要時,您總是可以覆蓋預設值。為了覆蓋 Spring Data for Pivotal GemFire 應用的預設值,引入了四個新的 Region 對映註解

  • @ClientRegion

  • @LocalRegion

  • @PartitionRegion

  • @ReplicateRegion

@ClientRegion 對映註解是客戶端應用程式特有的。上面列出的所有其他區域對映註解只能用於具有嵌入式對等 Cache 的伺服器應用程式。

客戶端應用程式有時需要建立和使用僅本地區域,也許是為了聚合來自其他區域的資料,以便在本地分析資料並執行應用程式代表使用者執行的某些功能。在這種情況下,資料不需要分發回伺服器,除非其他應用程式需要訪問結果。此區域甚至可以是臨時的,使用後即被丟棄,這可以透過區域本身的空閒超時 (TTI) 和生存時間 (TTL) 過期策略來實現。(有關過期策略的更多資訊,請參閱“配置過期”。)

區域級別的空閒超時(TTI)和生存時間(TTL)過期策略與條目級別的 TTI 和 TTL 過期策略是獨立的且不同的。

無論如何,如果您想建立一個僅本地的客戶端區域,其中資料不會分發回伺服器上具有相同名稱的相應區域,您可以宣告 @ClientRegion 對映註解並將 shortcut 屬性設定為 ClientRegionShortcut.LOCAL,如下所示

具有僅本地客戶端區域的 Spring ClientCache 應用程式
@ClientRegion(shortcut = ClientRegionShortcut.LOCAL)
class ClientLocalEntityType { .. }

所有區域型別特定註解都提供額外的屬性,這些屬性既在區域型別之間是通用的,也特定於該區域型別。例如,PartitionRegion 註解中的 collocatedWithredundantCopies 屬性僅適用於伺服器端 PARTITION 區域。

有關 Pivotal GemFire 區域型別的更多詳細資訊,請參見此處

6.12.2. 配置叢集定義區域

除了 @EnableEntityDefinedRegions 註解之外,Spring Data for Pivotal GemFire 還提供了反向註解 @EnableClusterDefinedRegions。與其根據應用程式用例 (UC) 和需求定義和驅動實體類來構建區域(最常見和邏輯的方法),您可以選擇從叢集中已定義的區域宣告您的區域,您的 ClientCache 應用程式將連線到該叢集。

這允許您將配置集中化,使用伺服器叢集作為資料定義的主要來源,並確保叢集的所有客戶端應用程式都具有一致的配置。這在快速擴充套件大量相同客戶端應用程式以處理雲管理環境中增加的負載時特別有用。

這個想法是,不是由客戶端應用程式驅動資料字典,而是使用者使用 Pivotal GemFire 的 Gfsh CLI shell 工具定義區域。這有一個額外的好處,即當向叢集新增額外的對等體時,它們也將擁有並共享相同的配置,因為 Pivotal GemFire 的 Cluster Configuration Service 會記住它。

例如,使用者可以在 Gfsh 中定義一個區域,如下所示

使用 Gfsh 定義區域
gfsh>create region --name=Books --type=PARTITION
 Member   | Status
--------- | --------------------------------------
ServerOne | Region "/Books" created on "ServerOne"
ServerTwo | Region "/Books" created on "ServerTwo"

gfsh>list regions
List of regions
---------------
Books

gfsh>describe region --name=/Books
..........................................................
Name            : Books
Data Policy     : partition
Hosting Members : ServerTwo
                  ServerOne

Non-Default Attributes Shared By Hosting Members

 Type  |    Name     | Value
------ | ----------- | ---------
Region | size        | 0
       | data-policy | PARTITION

藉助 Pivotal GemFire 的 Cluster Configuration Service,新增到伺服器叢集以處理增加的負載(在後端)的任何其他對等成員也將具有相同的配置,例如

向叢集新增額外的對等成員
gfsh>list members
  Name    | Id
--------- | ----------------------------------------------
Locator   | 10.0.0.121(Locator:68173:locator)<ec><v0>:1024
ServerOne | 10.0.0.121(ServerOne:68242)<v3>:1025
ServerTwo | 10.0.0.121(ServerTwo:68372)<v4>:1026

gfsh>start server --name=ServerThree --log-level=config --server-port=41414
Starting a Geode Server in /Users/you/geode/cluster/ServerThree...
...
Server in /Users/you/geode/cluster/ServerThree... on 10.0.0.121[41414] as ServerThree is currently online.
Process ID: 68467
Uptime: 3 seconds
Geode Version: 1.2.1
Java Version: 1.8.0_152
Log File: /Users/you/geode/cluster/ServerThree/ServerThree.log
JVM Arguments: -Dgemfire.default.locators=10.0.0.121[10334]
  -Dgemfire.use-cluster-configuration=true
  -Dgemfire.start-dev-rest-api=false
  -Dgemfire.log-level=config
  -XX:OnOutOfMemoryError=kill -KILL %p
  -Dgemfire.launcher.registerSignalHandlers=true
  -Djava.awt.headless=true
  -Dsun.rmi.dgc.server.gcInterval=9223372036854775806
Class-Path: /Users/you/geode/cluster/apache-geode-1.2.1/lib/geode-core-1.2.1.jar
  :/Users/you/geode/cluster/apache-geode-1.2.1/lib/geode-dependencies.jar

gfsh>list members
   Name     | Id
----------- | ----------------------------------------------
Locator     | 10.0.0.121(Locator:68173:locator)<ec><v0>:1024
ServerOne   | 10.0.0.121(ServerOne:68242)<v3>:1025
ServerTwo   | 10.0.0.121(ServerTwo:68372)<v4>:1026
ServerThree | 10.0.0.121(ServerThree:68467)<v5>:1027

gfsh>describe member --name=ServerThree
Name        : ServerThree
Id          : 10.0.0.121(ServerThree:68467)<v5>:1027
Host        : 10.0.0.121
Regions     : Books
PID         : 68467
Groups      :
Used Heap   : 37M
Max Heap    : 3641M
Working Dir : /Users/you/geode/cluster/ServerThree
Log file    : /Users/you/geode/cluster/ServerThree/ServerThree.log
Locators    : 10.0.0.121[10334]

Cache Server Information
Server Bind              :
Server Port              : 41414
Running                  : true
Client Connections       : 0

如您所見,“ServerThree”現在擁有“Books”區域。如果任何或所有伺服器宕機,它們在重新啟動時將擁有相同的配置以及“Books”區域。

在客戶端,可能會啟動許多書店客戶端應用程式例項來處理書店線上服務中的書籍。 “Books”區域可能是實現書店應用程式服務所需的許多不同區域之一。Spring Data for GemFire 允許從叢集定義客戶端應用程式區域,而不是必須單獨建立和配置每個區域,如下所示

使用 @EnableClusterDefinedRegions 從叢集定義客戶端區域
@ClientCacheApplication
@EnableClusterDefinedRegions
class BookStoreClientApplication {

    public static void main(String[] args) {
        ....
    }

    ...
}
@EnableClusterDefinedRegions 只能在客戶端使用。
您可以使用 clientRegionShortcut 註解屬性來控制在客戶端建立的區域型別。預設情況下,會建立一個客戶端 PROXY 區域。將 clientRegionShortcut 設定為 ClientRegionShortcut.CACHING_PROXY 以實現“近快取”。此設定適用於從叢集定義區域建立的所有客戶端區域。如果您想控制從叢集上定義的區域建立的客戶端區域的單個設定(如資料策略),那麼您可以實現一個 RegionConfigurer,其中包含基於區域名稱的自定義邏輯。

然後,在您的應用程式中使用“Books”區域變得很簡單。您可以直接注入“Books”區域,如下所示

使用“圖書”區域
@org.springframework.stereotype.Repository
class BooksDataAccessObject {

    @Resource(name = "Books")
    private Region<ISBN, Book> books;

    // implement CRUD and queries with the "Books" Region
}

或者,甚至可以根據應用程式域型別(實體)Book 定義 Spring Data Repository 定義,該定義對映到“Books”區域,如下所示

使用帶有 SD Repository 的“圖書”區域
interface BookRepository extends CrudRepository<Book, ISBN> {
    ...
}

然後,您可以將您的自定義 BooksDataAccessObjectBookRepository 注入到您的應用程式服務元件中,以執行所需的任何業務功能。

6.12.3. 配置驅逐

使用 Pivotal GemFire 管理資料是一項活躍的任務。通常需要進行調優,並且您必須結合使用多種功能(例如,驅逐和過期)才能有效地管理 Pivotal GemFire 中的記憶體資料。

鑑於 Pivotal GemFire 是一個記憶體資料網格 (IMDG),資料在記憶體中管理並分發到參與叢集的其他節點,以最大限度地減少延遲,最大化吞吐量並確保資料高度可用。由於並非所有應用程式的資料通常都能完全放入記憶體(即使在整個節點叢集中,更不用說單個節點上),您可以透過向叢集新增新節點來增加容量。這通常被稱為線性橫向擴充套件(而不是縱向擴充套件,後者意味著增加更多記憶體、更多 CPU、更多磁碟或更多網路頻寬——基本上是增加所有系統資源以處理負載)。

儘管如此,即使擁有一個節點叢集,通常也必須只在記憶體中保留最重要的資料。記憶體不足,甚至接近滿容量,很少是好事(如果曾發生過的話)。停止世界的 GC 或更糟糕的 OutOfMemoryErrors 會使您的應用程式戛然而止。

因此,為了幫助管理記憶體並保留最重要的資料,Pivotal GemFire 支援最近最少使用 (LRU) 驅逐。也就是說,Pivotal GemFire 根據區域條目上次訪問的時間使用最近最少使用演算法驅逐區域條目。

要啟用驅逐,請使用 @EnableEviction 註解應用程式類,如下所示

已啟用驅逐的 Spring 應用程式
@SpringBootApplication
@PeerCacheApplication
@EnableEviction(policies = {
    @EvictionPolicy(regionNames = "Books", action = EvictionActionType.INVALIDATE),
    @EvictionPolicy(regionNames = { "Customers", "Orders" }, maximum = 90,
        action = EvictionActionType.OVERFLOW_TO_DISK,
        type = EvictonPolicyType.HEAP_PERCENTAGE)
})
class ServerApplication { .. }

驅逐策略通常設定在伺服器中的區域上。

如前所示,policies 屬性可以指定一個或多個巢狀的 @EvictionPolicy 註解,每個註解都單獨適用於一個或多個需要應用驅逐策略的區域。

此外,您可以引用 Pivotal GemFire 的 org.apache.geode.cache.util.ObjectSizer 介面的自定義實現,該實現可以在 Spring 容器中定義為 bean,並透過使用 objectSizerName 屬性按名稱引用。

ObjectSizer 允許您定義用於評估和確定儲存在區域中的物件大小的標準。

有關驅逐配置選項的完整列表,請參閱 @EnableEviction 註解 Javadoc

有關 Pivotal GemFire 驅逐的更多詳細資訊,請參見此處

6.12.4. 配置過期

除了驅逐,過期也可以透過允許儲存在區域中的條目過期來管理記憶體。Pivotal GemFire 支援生存時間 (TTL) 和空閒超時 (TTI) 條目過期策略。

Spring Data for Pivotal GemFire 基於註解的過期配置基於 Spring Data for Pivotal GemFire 1.5 版中新增的早期和現有條目過期註解支援

本質上,Spring Data for Pivotal GemFire 的過期註解支援基於 Pivotal GemFire org.apache.geode.cache.CustomExpiry 介面的自定義實現。此 o.a.g.cache.CustomExpiry 實現檢查儲存在區域中的使用者應用程式域物件是否存在型別級別的過期註解。

Spring Data for Pivotal GemFire 提供以下過期註解

  • 過期

  • IdleTimeoutExpiration

  • TimeToLiveExpiration

一個應用程式域物件型別可以被一個或多個過期註解註釋,如下所示

應用程式域物件特定的過期策略
@Region("Books")
@TimeToLiveExpiration(timeout = 30000, action = "INVALIDATE")
class Book { .. }

要啟用過期,請使用 @EnableExpiration 註解應用程式類,如下所示

已啟用過期的 Spring 應用程式
@SpringBootApplication
@PeerCacheApplication
@EnableExpiration
class ServerApplication { .. }

除了應用程式域物件型別級別的過期策略之外,您還可以使用 @EnableExpiration 註解直接和單獨配置基於區域的過期策略,如下所示

具有區域特定過期策略的 Spring 應用程式
@SpringBootApplication
@PeerCacheApplication
@EnableExpiration(policies = {
    @ExpirationPolicy(regionNames = "Books", types = ExpirationType.TIME_TO_LIVE),
    @ExpirationPolicy(regionNames = { "Customers", "Orders" }, timeout = 30000,
        action = ExpirationActionType.LOCAL_DESTROY)
})
class ServerApplication { .. }

前面的示例設定了 BooksCustomersOrders 區域的過期策略。

過期策略通常設定在伺服器中的區域上。

有關過期配置選項的完整列表,請參閱 @EnableExpiration 註解 Javadoc

有關 Pivotal GemFire 過期的更多詳細資訊,請參見此處

6.12.5. 配置壓縮

除了驅逐過期之外,您還可以為資料區域配置壓縮以減少記憶體消耗。

Pivotal GemFire 允許您透過使用可插拔的 Compressors 或不同的壓縮編解碼器來壓縮記憶體中的 Region 值。Pivotal GemFire 預設使用 Google 的 Snappy 壓縮庫。

要啟用壓縮,請使用 @EnableCompression 註解應用程式類,如下所示

啟用 Region 壓縮的 Spring 應用程式
@SpringBootApplication
@ClientCacheApplication
@EnableCompression(compressorBeanName = "MyCompressor", regionNames = { "Customers", "Orders" })
class ClientApplication { .. }
compressorBeanNameregionNames 屬性都不是必需的。

compressorBeanName 預設為 SnappyCompressor,啟用 Pivotal GemFire 的 SnappyCompressor

regionNames 屬性是一個 Region 名稱陣列,指定了啟用壓縮的 Region。預設情況下,如果未顯式設定 regionNames 屬性,所有 Region 都會壓縮值。

或者,您可以在 application.properties 檔案中使用 spring.data.gemfire.cache.compression.compressor-bean-namespring.data.gemfire.cache.compression.region-names 屬性來設定和配置這些 @EnableCompression 註解屬性的值。
要使用 Pivotal GemFire 的 Region 壓縮功能,您必須在應用程式的 pom.xml 檔案(對於 Maven)或 build.gradle 檔案(對於 Gradle)中包含 org.iq80.snappy:snappy 依賴項。這僅在您使用 Pivotal GemFire 對 Region 壓縮的預設支援時才需要,該支援預設使用 SnappyCompressor。當然,如果您使用其他壓縮庫,則需要在應用程式的類路徑中包含該壓縮庫的依賴項。此外,您需要實現 Pivotal GemFire 的 Compressor 介面來適應您選擇的壓縮庫,將其定義為 Spring 壓縮器中的 bean,並將 compressorBeanName 設定為此自定義 bean 定義。

有關更多詳細資訊,請參見 @EnableCompression 註解 Javadoc

有關 Pivotal GemFire 壓縮的更多詳細資訊,請參見此處

6.12.6. 配置堆外記憶體

減少 JVM 堆記憶體壓力並最小化 GC 活動的另一種有效方法是使用 Pivotal GemFire 的堆外記憶體支援。

Region 條目不儲存在 JVM 堆上,而是儲存在系統的主記憶體中。正如 Pivotal GemFire 使用者指南中所述,當儲存的物件大小統一、大多小於 128K 且不需要頻繁反序列化時,堆外記憶體通常效果最好。

要啟用堆外,請使用 @EnableOffHeap 註解應用程式類,如下所示

啟用堆外的 Spring 應用程式
@SpringBootApplication
@PeerCacheApplication
@EnableOffHeap(memorySize = 8192m regionNames = { "Customers", "Orders" })
class ServerApplication { .. }

memorySize 屬性是必需的。memorySize 屬性的值指定 Region 可以使用的主記憶體量,以兆位元組 (m) 或千兆位元組 (g) 為單位。

regionNames 屬性是一個 Region 名稱陣列,指定了在主記憶體中儲存條目的 Region。預設情況下,如果未顯式設定 regionNames 屬性,所有 Region 都使用主記憶體。

或者,您可以在 application.properties 檔案中使用 spring.data.gemfire.cache.off-heap.memory-sizespring.data.gemfire.cache.off-heap.region-names 屬性來設定和配置這些 @EnableOffHeap 註解屬性的值。

有關更多詳細資訊,請參見 @EnableOffHeap 註解 Javadoc

6.12.7. 配置磁碟儲存

或者,您可以將 Region 配置為將資料持久化到磁碟。您還可以將 Region 配置為在逐出 Region 條目時將資料溢位到磁碟。在這兩種情況下,都需要 DiskStore 來持久化和/或溢位資料。當沒有為具有永續性或溢位的 Region 配置顯式 DiskStore 時,Pivotal GemFire 使用 DEFAULT DiskStore

我們建議在將資料持久化和/或溢位到磁碟時定義特定於 Region 的 DiskStores

Spring Data for Pivotal GemFire 提供註解支援,透過使用 @EnableDiskStore@EnableDiskStores 註解應用程式類來定義和建立應用程式 Region DiskStores

@EnableDiskStores 是一個複合註解,用於聚合一個或多個 @EnableDiskStore 註解。

例如,雖然 Book 資訊可能主要由來自某些外部資料來源(如 Amazon)的引用資料組成,但 Order 資料很可能具有事務性,並且是應用程式需要保留的資料(如果事務量足夠高,甚至可能溢位到磁碟)——至少任何圖書出版商和作者都希望如此。

使用 @EnableDiskStore 註解,您可以如下定義和建立 DiskStore

定義 DiskStore 的 Spring 應用程式
@SpringBootApplication
@PeerCacheApplication
@EnableDiskStore(name = "OrdersDiskStore", autoCompact = true, compactionThreshold = 70,
    maxOplogSize = 512, diskDirectories = @DiskDiretory(location = "/absolute/path/to/order/disk/files"))
class ServerApplication { .. }

同樣,可以使用複合註解 @EnableDiskStores 定義多個 DiskStore

與 Spring Data for Pivotal GemFire 基於註解的配置模型中的其他註解一樣,@EnableDiskStore@EnableDiskStores 都有許多屬性以及相關的配置屬性,用於在執行時自定義建立的 DiskStores

此外,@EnableDiskStores 註解定義了適用於所有從 @EnableDiskStore 註解建立的 DiskStore 的某些常見 DiskStore 屬性,這些註解與 @EnableDiskStores 註解本身組合。單個 DiskStore 配置會覆蓋特定的全域性設定,但 @EnableDiskStores 註解方便地定義了適用於該註解聚合的所有 DiskStore 的常見配置屬性。

Spring Data for Pivotal GemFire 還提供了 DiskStoreConfigurer 回撥介面,可以在 Java 配置中宣告並用於代替配置屬性在執行時自定義 DiskStore,如下例所示

具有自定義 DiskStore 配置的 Spring 應用程式
@SpringBootApplication
@PeerCacheApplication
@EnableDiskStore(name = "OrdersDiskStore", autoCompact = true, compactionThreshold = 70,
    maxOplogSize = 512, diskDirectories = @DiskDiretory(location = "/absolute/path/to/order/disk/files"))
class ServerApplication {

  @Bean
  DiskStoreConfigurer ordersDiskStoreDiretoryConfigurer(
          @Value("${orders.disk.store.location}") String location) {

      return (beanName, diskStoreFactoryBean) -> {

          if ("OrdersDiskStore".equals(beanName) {
              diskStoreFactoryBean.setDiskDirs(Collections.singletonList(new DiskDir(location));
          }
      }
  }
}

有關可用屬性以及相關配置屬性的更多詳細資訊,請參見 @EnableDiskStore@EnableDiskStores 註解 Javadoc。

有關 Pivotal GemFire Region 永續性和溢位(使用 DiskStores)的更多詳細資訊,請參見此處

6.12.8. 配置索引

除非資料可以訪問,否則將資料儲存在 Region 中沒有多大用處。

除了 Region.get(key) 操作(特別是在預先知道鍵的情況下),資料通常透過對包含資料的 Region 執行查詢來檢索。使用 Pivotal GemFire,查詢是使用物件查詢語言 (OQL) 編寫的,客戶端希望訪問的特定資料集在查詢的謂詞中表達(例如,SELECT * FROM /Books b WHERE b.author.name = 'Jon Doe')。

通常,沒有索引的查詢效率低下。在沒有索引的情況下執行查詢時,Pivotal GemFire 執行相當於全表掃描的操作。

索引是為查詢謂詞中使用的物件上的欄位建立和維護的,以匹配查詢投影所表達的感興趣的資料。可以建立不同型別的索引,例如索引和雜湊索引。

Spring Data for Pivotal GemFire 使得在儲存和訪問資料的 Region 上建立索引變得容易。我們不再像以前那樣透過使用 Spring 配置顯式宣告 Index bean 定義,而是可以在 Java 中建立 Index bean 定義,如下所示

使用 Java 配置的索引 bean 定義
@Bean("BooksIsbnIndex")
IndexFactoryBean bookIsbnIndex(GemFireCache gemfireCache) {

    IndexFactoryBean bookIsbnIndex = new IndexFactoryBean();

    bookIsbnIndex.setCache(gemfireCache);
    bookIsbnIndex.setName("BookIsbnIndex");
    bookIsbnIndex.setExpression("isbn");
    bookIsbnIndex.setFrom("/Books"));
    bookIsbnIndex.setType(IndexType.KEY);

    return bookIsbnIndex;
}

或者,我們可以使用 XML 建立 Index bean 定義,如下所示

使用 XML 的索引 bean 定義
<gfe:index id="BooksIsbnIndex" expression="isbn" from="/Books" type="KEY"/>

但是,現在您可以直接在應用程式域物件型別的欄位上定義索引,您知道這些欄位將用於查詢謂詞以加快這些查詢的速度。您甚至可以為應用程式儲存庫介面上使用者定義查詢方法生成的 OQL 查詢應用索引。

重新使用前面示例中的 Book 實體類,我們可以使用 @Indexed 註解 Book 上我們知道在 BookRepository 介面中用查詢方法定義的查詢中使用的欄位,如下所示

使用索引建模書籍的應用程式域物件型別
@Region("Books")
class Book {

  @Id
  private ISBN isbn;

  @Indexed
  private Author author;

  private Category category;

  private LocalDate releaseDate;

  private Publisher publisher;

  @LuceneIndexed
  private String title;

}

在我們的新 Book 類定義中,我們使用 @Indexed 註解了 author 欄位,並使用 @LuceneIndexed 註解了 title 欄位。此外,isbn 欄位之前已用 Spring Data 的 @Id 註解,該註解標識了包含 Book 例項唯一識別符號的欄位,並且在 Spring Data for Pivotal GemFire 中,@Id 註解欄位或屬性在儲存條目時用作 Region 中的鍵。

  • @Id 註解欄位或屬性會導致建立 Pivotal GemFire KEY 索引。

  • @Indexed 註解欄位或屬性會導致建立 Pivotal GemFire HASH 索引(預設)。

  • @LuceneIndexed 註解欄位或屬性會導致建立 Pivotal GemFire Lucene 索引,用於使用 Pivotal GemFire 的 Lucene 整合和支援進行基於文字的搜尋。

@Indexed 註解在未設定任何屬性的情況下使用時,索引的 nameexpressionfromClause 派生自添加了 @Indexed 註解的類的欄位或屬性。expression 就是欄位或屬性的名稱。fromClause 派生自域物件類上的 @Region 註解,如果未指定 @Region 註解,則派生自域物件類的簡單名稱。

當然,您可以顯式設定任何 @Indexed 註解屬性以覆蓋 Spring Data for Pivotal GemFire 提供的預設值。

使用自定義索引建模書籍的應用程式域物件型別
@Region("Books")
class Book {

  @Id
  private ISBN isbn;

  @Indexed(name = "BookAuthorNameIndex", expression = "author.name", type = "FUNCTIONAL")
  private Author author;

  private Category category;

  private LocalDate releaseDate;

  private Publisher publisher;

  @LuceneIndexed(name = "BookTitleIndex", destory = true)
  private String title;

}

索引的 name(未顯式設定時自動生成)也用作在 Spring 容器中為索引註冊的 bean 的名稱。如有必要,此索引 bean 甚至可以透過名稱注入到另一個應用程式元件中。

生成的索引名稱遵循此模式:<Region Name><Field/Property Name><Index Type>Idx。例如,author 索引的名稱將是 BooksAuthorHashIdx

要啟用索引,請使用 @EnableIndexing 註解應用程式類,如下所示

啟用索引的 Spring 應用程式
@SpringBootApplication
@PeerCacheApplication
@EnableEntityDefinedRegions
@EnableIndexing
class ServerApplication { .. }
除非同時宣告 @EnableEntityDefinedRegions,否則 @EnablingIndexing 註解無效。實質上,索引是從實體類型別上的欄位或屬性定義的,並且必須掃描實體類以檢查實體欄位和屬性是否存在索引註解。如果沒有此掃描,則無法找到索引註解。我們還強烈建議您限制掃描範圍。

雖然 Spring Data for Pivotal GemFire 儲存庫尚不支援 Lucene 查詢,但 SDG 透過使用熟悉的 Spring 模板設計模式為 Pivotal GemFire Lucene 查詢提供了全面的支援

最後,我們以一些額外的提示來結束本節,在使用索引時請記住這些提示

  • 雖然執行 OQL 查詢不需要 OQL 索引,但執行 Lucene 基於文字的搜尋需要 Lucene 索引。

  • OQL 索引不會持久化到磁碟。它們只在記憶體中維護。因此,當 Pivotal GemFire 節點重新啟動時,必須重建索引。

  • 您還需要注意維護索引相關的開銷,特別是因為索引完全儲存在記憶體中,尤其是在 Region 條目更新時。索引“維護”可以配置為非同步任務。

當您的 Spring 應用程式重新啟動時,索引必須重建,您可以使用的另一個最佳化是首先預先定義所有索引,然後一次性建立所有索引,這在 Spring Data for Pivotal GemFire 中發生在 Spring 容器重新整理時。

您可以透過將 @EnableIndexing 註解上的 define 屬性設定為 true 來預先定義索引,然後一次性建立它們。

有關更多詳細資訊,請參見 Pivotal GemFire 使用者指南中的 “一次建立多個索引”

建立合理的索引是一項重要的任務,因為設計不當的索引可能弊大於利。

有關配置選項的完整列表,請參見 @Indexed 註解和 @LuceneIndexed 註解 Javadoc。

有關 Pivotal GemFire OQL 查詢的更多詳細資訊,請參見此處

有關 Pivotal GemFire 索引的更多詳細資訊,請參見此處

有關 Pivotal GemFire Lucene 查詢的更多詳細資訊,請參見此處

6.13. 配置連續查詢

Pivotal GemFire 的另一個非常重要和有用的功能是 連續查詢

在支援網際網路的萬物互聯世界中,事件和資料流無處不在。能夠即時處理大量資料流並對事件作出反應是許多應用程式日益重要的需求。一個例子是自動駕駛汽車。能夠即時接收、過濾、轉換、分析和處理資料是即時應用程式的關鍵區別和特徵。

幸運的是,Pivotal GemFire 在這方面超前於時代。透過使用連續查詢 (CQ),客戶端應用程式可以表達它感興趣的資料或事件,並註冊監聽器以在事件發生時處理和處理這些事件。客戶端應用程式可能感興趣的資料以 OQL 查詢的形式表示,其中查詢謂詞用於過濾或識別感興趣的資料。當資料更改或新增並與註冊的 CQ 的查詢謂詞中定義的條件匹配時,客戶端應用程式將收到通知。

Spring Data for Pivotal GemFire 使得定義和註冊 CQ 以及相關的監聽器以處理和處理 CQ 事件變得容易,而無需 Pivotal GemFire 的所有冗餘管道。SDG 新的基於註解的 CQ 配置建立在 連續查詢監聽器容器中現有連續查詢支援的基礎上。

例如,假設圖書出版商希望註冊興趣並在任何時候 Book 的訂單(需求)超過當前庫存(供應)時收到通知。然後出版商的列印應用程式可能會註冊以下 CQ

帶有已註冊 CQ 和監聽器的 Spring ClientCache 應用程式。
@SpringBootApplication
@ClientCacheApplication(subcriptionEnabled = true)
@EnableContinuousQueries
class PublisherPrintApplication {

    @ContinuousQuery(name = "DemandExceedsSupply", query =
       "SELECT book.* FROM /Books book, /Inventory inventory
        WHERE book.title = 'How to crush it in the Book business like Amazon"
        AND inventory.isbn = book.isbn
        AND inventory.available < (
            SELECT sum(order.lineItems.quantity)
            FROM /Orders order
            WHERE order.status = 'pending'
            AND order.lineItems.isbn = book.isbn
        )
    ")
    void handleSupplyProblem(CqEvent event) {
        // start printing more books, fast!
    }
}

要啟用連續查詢,請使用 @EnableContinuousQueries 註解您的應用程式類。

定義連續查詢包括使用 @ContinuousQuery 註解任何 Spring @Component 註解的 POJO 類方法(與 SDG 的 Function 註解的 POJO 方法類似)。使用 @ContinuousQuery 註解定義的帶有 CQ 的 POJO 方法在任何時候新增或更改與查詢謂詞匹配的資料時都會被呼叫。

此外,POJO 方法簽名應遵循 ContinuousQueryListenerContinuousQueryListenerAdapter 部分中概述的要求。

有關可用屬性和配置設定的更多詳細資訊,請參見 @EnableContinuousQueries@ContinuousQuery 註解 Javadoc。

有關 Spring Data for Pivotal GemFire 連續查詢支援的更多詳細資訊,請參見此處

有關 Pivotal GemFire 連續查詢的更多詳細資訊,請參見此處

6.14. 配置 Spring 的快取抽象

透過 Spring Data for Pivotal GemFire,Pivotal GemFire 可以用作 Spring 快取抽象中的快取提供程式。

在 Spring 的快取抽象中,快取註解(例如 @Cacheable)標識在呼叫可能昂貴的操作之前執行快取查詢的快取。應用程式服務方法的結果在操作呼叫後被快取。

在 Spring Data for Pivotal GemFire 中,Spring Cache 直接對應於 Pivotal GemFire Region。在呼叫任何快取註解的應用程式服務方法之前,Region 必須存在。這適用於 Spring 的任何快取註解(即 @Cacheable@CachePut@CacheEvict),這些註解標識在服務操作中使用的快取。

例如,我們的出版商的銷售點 (PoS) 應用程式可能具有一項功能,用於在銷售交易期間確定或查詢 BookPrice,如下例所示

@Service
class PointOfSaleService

  @Cacheable("BookPrices")
  Price runPriceCheckFor(Book book) {
      ...
  }

  @Transactional
  Receipt checkout(Order order) {
      ...
  }

  ...
}

為了讓您在使用 Spring Data for Pivotal GemFire 和 Spring 的快取抽象時更輕鬆,基於註解的配置模型中添加了兩個新功能。

考慮以下 Spring 快取配置

使用 Pivotal GemFire 作為快取提供程式啟用快取
@EnableCaching
class CachingConfiguration {

  @Bean
  GemfireCacheManager cacheManager(GemFireCache gemfireCache) {

      GemfireCacheManager cacheManager = new GemfireCacheManager();

      cacheManager.setCache(gemfireCache);

      return cacheManager;
  }

  @Bean("BookPricesCache")
  ReplicatedRegionFactoryBean<Book, Price> bookPricesRegion(GemFireCache gemfireCache) {

    ReplicatedRegionFactoryBean<Book, Price> bookPricesRegion =
        new ReplicatedRegionFactoryBean<>();

    bookPricesRegion.setCache(gemfireCache);
    bookPricesRegion.setClose(false);
    bookPricesRegion.setPersistent(false);

    return bookPricesRegion;
  }

  @Bean("PointOfSaleService")
  PointOfSaleService pointOfSaleService(..) {
      return new PointOfSaleService(..);
  }
}

使用 Spring Data for Pivotal GemFire 的新功能,您可以將相同的快取配置簡化為以下內容

啟用 Pivotal GemFire 快取
@EnableGemfireCaching
@EnableCachingDefinedRegions
class CachingConfiguration {

  @Bean("PointOfSaleService")
  PointOfSaleService pointOfSaleService(..) {
      return new PointOfSaleService(..);
  }
}

首先,@EnableGemfireCaching 註解取代了 Spring @EnableCaching 註解以及在 Spring 配置中宣告顯式 CacheManager bean 定義(名為“cacheManager”)的需要。

其次,@EnableCachingDefinedRegions 註解,就像“配置 Region”中描述的 @EnableEntityDefinedRegions 註解一樣,檢查整個 Spring 應用程式,快取註解的服務元件以識別應用程式在執行時需要的所有快取,並在應用程式啟動時為這些快取在 Pivotal GemFire 中建立 Region。

建立的 Region 是建立 Region 的應用程式程序的本地 Region。如果應用程式是對等 Cache,則 Region 僅存在於應用程式節點上。如果應用程式是 ClientCache,則 SDG 會建立客戶端 PROXY Region,並期望那些同名的 Region 已經存在於叢集中的伺服器上。

SDG 無法使用 Spring CacheResolver 在執行時解析操作中使用的快取來確定服務方法所需的快取。
SDG 還支援應用程式服務元件上的 JCache (JSR-107) 快取註解。有關代替 JCache 快取註解使用的等效 Spring 快取註解,請參見核心 Spring Framework 參考指南

有關在 Spring 的快取抽象中使用 Pivotal GemFire 作為快取提供程式的更多詳細資訊,請參閱 “Spring 快取抽象支援” 部分。

有關 Spring 的快取抽象的更多詳細資訊,請參見此處

6.15. 配置叢集配置推送

這可能是 Spring Data for Pivotal GemFire 中最令人興奮的新功能。

當客戶端應用程式類用 @EnableClusterConfiguration 註解時,客戶端應用程式在 Spring 容器中定義和宣告為 bean 的任何 Region 或索引都會“推送”到客戶端連線到的伺服器叢集。不僅如此,這個“推送”是以 Pivotal GemFire 在使用 HTTP 時記住客戶端推送的配置的方式執行的。如果叢集中的所有節點都宕機了,它們會以與之前相同的配置重新啟動。如果叢集中添加了新伺服器,它將獲取相同的配置。

從某種意義上說,此功能與您使用 Gfsh 手動在叢集中的所有伺服器上建立 Region 和索引並沒有太大區別。只是現在,使用 Spring Data for Pivotal GemFire,您不再需要使用 Gfsh 來建立 Region 和索引。您的 Spring Boot 應用程式,藉助 Spring Data for Pivotal GemFire 的強大功能,已經包含建立 Region 和索引所需的所有配置元資料。

當您使用 Spring Data Repository 抽象時,我們知道您的應用程式需要的所有 Region(例如由 @Region 註解的實體類定義的 Region)和索引(例如由 @Indexed 註解的實體欄位和屬性定義的索引)。

當您使用 Spring 的快取抽象時,我們還知道您的應用程式服務元件所需的所有快取的所有 Region。

本質上,您只需透過使用 Spring Framework 的所有 API 和功能來開發您的應用程式,無論是在註解元資料、Java、XML 還是其他方式中表達,也無論是用於配置、對映還是其他目的,您就已經告訴了我們所有需要知道的資訊。

關鍵是,您可以專注於應用程式的業務邏輯,同時使用框架的功能和支援基礎設施(例如 Spring 的快取抽象、Spring Data Repositories、Spring 的事務管理等),而 Spring Data for Pivotal GemFire 會為您處理這些框架功能所需的所有 Pivotal GemFire 管道。

將配置從客戶端推送到叢集中的伺服器並讓叢集記住它,部分得益於 Pivotal GemFire 叢集配置服務的使用。Pivotal GemFire 的叢集配置服務也是 Gfsh 用於記錄使用者從 shell 傳送到叢集的與模式相關的更改(例如,gfsh> create region --name=Example --type=PARTITION)的相同服務。

當然,由於叢集可能會“記住”客戶端從之前執行中推送的先前配置,因此 Spring Data for Pivotal GemFire 會小心,不要覆蓋伺服器中已定義的任何現有 Region 和索引。例如,當 Region 已經包含資料時,這尤其重要!

目前,沒有選項可以覆蓋任何現有的 Region 或 Index 定義。要重新建立 Region 或 Index,您必須使用 Gfsh 先銷燬 Region 或 Index,然後重新啟動客戶端應用程式,以便將配置再次推送到伺服器。或者,您可以使用 Gfsh 手動(重新)定義 Region 和 Index。
Gfsh 不同,Spring Data for Pivotal GemFire 僅支援從客戶端在伺服器上建立 Region 和索引。對於高階配置和用例,您應該使用 Gfsh 來管理(伺服器端)叢集。
要使用此功能,您必須在 Spring、Pivotal GemFire ClientCache 應用程式的類路徑中顯式宣告 org.springframework:spring-web 依賴項。

考慮以下配置中表達的強大功能

Spring ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication
@EnableCachingDefinedRegions
@EnableEntityDefinedRegions
@EnableIndexing
@EnableGemfireCaching
@EnableGemfireRepositories
@EnableClusterConfiguration
class ClientApplication { .. }

您可以立即獲得一個 Spring Boot 應用程式,其中包含 Pivotal GemFire ClientCache 例項、Spring Data Repositories、使用 Pivotal GemFire 作為快取提供程式的 Spring 快取抽象(其中 Region 和索引不僅在客戶端建立,而且推送到叢集中的伺服器)。

從那裡,您只需要執行以下操作

  • 定義應用程式的域模型物件,並使用對映和索引註解進行註解。

  • 為每個實體型別定義儲存庫介面以支援基本資料訪問操作和簡單查詢。

  • 定義包含事務處理實體的業務邏輯的服務元件。

  • 在需要快取、事務行為等的服務方法上宣告適當的註解。

在這種情況下,沒有任何內容與應用程式後端服務(例如 Pivotal GemFire)所需的基礎設施和管道有關。資料庫使用者具有類似的功能。現在 Spring 和 Pivotal GemFire 開發人員也具有了。

當與以下 Spring Data for Pivotal GemFire 註解結合使用時,此應用程式將以很少的努力真正開始騰飛

  • @EnableContinuousQueries

  • @EnableGemfireFunctionExecutions

  • @EnableGemfireCacheTransactions

有關更多詳細資訊,請參見 @EnableClusterConfiguration 註解 Javadoc

6.16. 配置 SSL

與透過網路傳輸資料同樣重要的是保護傳輸中的資料。當然,在 Java 中實現此目的的常用方法是使用安全套接字擴充套件 (SSE) 和傳輸層安全 (TLS)。

要啟用 SSL,請使用 @EnableSsl 註解您的應用程式類,如下所示

啟用 SSL 的 Spring ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication
@EnableSsl
public class ClientApplication { .. }

然後,您需要設定必要的 SSL 配置屬性或屬性:金鑰庫、使用者名稱/密碼等。

您可以單獨為不同的 Pivotal GemFire 元件(GATEWAYHTTPJMXLOCATORSERVER)配置 SSL,也可以透過使用 CLUSTER 列舉值來集體配置它們以使用 SSL。

您可以透過使用巢狀的 @EnableSsl 註解的 components 屬性和 Component 列舉中的列舉值來指定 SSL 配置設定應應用於哪些 Pivotal GemFire 元件,如下所示

按元件啟用 SSL 的 Spring ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication
@EnableSsl(components = { GATEWAY, LOCATOR, SERVER })
public class ClientApplication { .. }

此外,您還可以透過使用相應的註解屬性或相關配置屬性來指定元件級別的 SSL 配置(ciphersprotocolskeystore/truststore 資訊)。

有關更多詳細資訊,請參見 @EnableSsl 註解 Javadoc

有關 Pivotal GemFire SSL 支援的更多詳細資訊,請參見此處

6.17. 配置安全性

毫無疑問,應用程式安全性極其重要,Spring Data for Pivotal GemFire 為保護 Pivotal GemFire 客戶端和伺服器提供了全面的支援。

最近,Pivotal GemFire 引入了一個新的 整合安全 框架(取代了其舊的身份驗證和授權安全模型),用於處理身份驗證和授權。這個新安全框架的主要功能和優點之一是它與 Apache Shiro 整合,因此可以委託身份驗證和授權請求給 Apache Shiro 來強制執行安全性。

本節的其餘部分演示了 Spring Data for Pivotal GemFire 如何進一步簡化 Pivotal GemFire 的安全故事。

6.17.1. 配置伺服器安全性

您可以通過幾種不同的方式配置 Pivotal GemFire 叢集中伺服器的安全性。

  • 實現 Pivotal GemFire org.apache.geode.security.SecurityManager 介面,並將 Pivotal GemFire 的 security-manager 屬性設定為使用完全限定類名引用您的應用程式 SecurityManager 實現。或者,使用者可以構造並初始化其 SecurityManager 實現的例項,並在建立 Pivotal GemFire 對等 Cache 時使用 CacheFactory.setSecurityManager(:SecurityManager) 方法進行設定。

  • 建立一個 Apache Shiro shiro.ini 檔案,其中包含為您的應用程式定義的使用者、角色和許可權,然後將 Pivotal GemFire security-shiro-init 屬性設定為引用此 shiro.ini 檔案,該檔案必須在 CLASSPATH 中可用。

  • 僅使用 Apache Shiro,使用 Spring Data for Pivotal GemFire 的新 @EnableSecurity 註解您的 Spring Boot 應用程式類,並在 Spring 容器中將一個或多個 Apache Shiro Realm 定義為 bean,以訪問您的應用程式的安全元資料(即授權使用者、角色和許可權)。

第一種方法的問題是您必須實現自己的 SecurityManager,這可能非常繁瑣且容易出錯。實現自定義 SecurityManager 提供了一些靈活性,可以從儲存元資料的任何資料來源(例如 LDAP 甚至專有內部資料來源)訪問安全元資料。但是,這個問題已經透過配置和使用 Apache Shiro Realms 解決了,後者更普遍為人所知且不特定於 Pivotal GemFire。

請參閱 Pivotal GemFire 的身份驗證授權安全示例,作為實現您自己的自定義應用程式特定 SecurityManager 的一種可能方法。但是,我們強烈**不**建議這樣做。

第二種方法,使用 Apache Shiro INI 檔案,略好一些,但您仍然需要首先熟悉 INI 檔案格式。此外,INI 檔案是靜態的,並且在執行時不易更新。

第三種方法是最理想的,因為它遵循廣為人知和行業接受的概念(即 Apache Shiro 的安全框架),並且易於設定,如下例所示

使用 Apache Shiro 的 Spring 伺服器應用程式
@SpringBootApplication
@CacheServerApplication
@EnableSecurity
class ServerApplication {

  @Bean
  PropertiesRealm shiroRealm() {

      PropertiesRealm propertiesRealm = new PropertiesRealm();

      propertiesRealm.setResourcePath("classpath:shiro.properties");
      propertiesRealm.setPermissionResolver(new GemFirePermissionResolver());

      return propertiesRealm;
  }
}
上面示例中配置的 Realm 很容易是 Apache Shiro 支援的任何 Realms

您甚至可以建立 Apache Shiro Realm 的自定義實現。

有關更多詳細資訊,請參見 Apache Shiro 的Realm 文件

當 Apache Shiro 在叢集伺服器的 CLASSPATH 上,並且一個或多個 Apache Shiro Realms 已在 Spring 容器中定義為 bean 時,Spring Data for Pivotal GemFire 會檢測此配置並在使用 @EnableSecurity 註解時使用 Apache Shiro 作為安全提供程式來保護您的 Pivotal GemFire 伺服器。

有關 Spring Data for Pivotal GemFire 對使用 Apache Shiro 的 Pivotal GemFire 新整合安全框架的支援的更多資訊,請參閱此spring.io 部落格文章

有關可用屬性和相關配置屬性的更多詳細資訊,請參見 @EnableSecurity 註解 Javadoc。

有關 Pivotal GemFire 安全性的更多詳細資訊,請參見此處

6.17.2. 配置客戶端安全性

如果不討論如何保護基於 Spring 的 Pivotal GemFire 快取客戶端應用程式,安全故事將不完整。

Pivotal GemFire 保護客戶端應用程式的過程坦率地說相當複雜。簡而言之,您需要

  1. 提供 org.apache.geode.security.AuthInitialize 介面的實現。

  2. 將 Pivotal GemFire security-client-auth-init(系統)屬性設定為引用自定義的、應用程式提供的 AuthInitialize 介面。

  3. 在專有的 Pivotal GemFire gfsecurity.properties 檔案中指定使用者憑據。

Spring Data for Pivotal GemFire 透過使用與伺服器應用程式中相同的 @EnableSecurity 註解來簡化所有這些步驟。換句話說,相同的 @EnableSecurity 註解處理客戶端和伺服器應用程式的安全性。此功能使使用者更容易在決定將其應用程式從嵌入式對等 Cache 應用程式切換到 ClientCache 應用程式時,例如。只需將 SDG 註解從 @PeerCacheApplication@CacheServerApplication 更改為 @ClientCacheApplication,您就完成了。

實際上,您需要在客戶端執行的操作如下

使用 @EnableSecurity 的 Spring 客戶端應用程式
@SpringBootApplication
@ClientCacheApplication
@EnableSecurity
class ClientApplication { .. }

然後您可以定義包含所需使用者名稱和密碼的熟悉的 Spring Boot application.properties 檔案,如下例所示,您就全部設定好了

帶有所需安全憑據的 Spring Boot application.properties 檔案
spring.data.gemfire.security.username=jackBlack
spring.data.gemfire.security.password=b@cK!nB1@cK
預設情況下,當 application.properties 檔案放置在應用程式 CLASSPATH 的根目錄中時,Spring Boot 可以找到它。當然,Spring 支援使用其 Resource 抽象來定位資源的多種方式。

有關可用屬性和相關配置屬性的更多詳細資訊,請參見 @EnableSecurity 註解 Javadoc。

有關 Pivotal GemFire 安全性的更多詳細資訊,請參見此處

6.18. 配置技巧

以下技巧可以幫助您充分利用新的基於註解的配置模型

6.18.1. 配置組織

正如我們在 “配置叢集配置推送” 一節中看到的,當透過註解啟用許多 Pivotal GemFire 或 Spring Data for Pivotal GemFire 功能時,我們開始在 Spring @Configuration@SpringBootApplication 類上堆疊大量註解。在這種情況下,開始將配置進行一些模組化是合理的。

例如,考慮以下宣告

具有所有功能的 Spring ClientCache 應用程式
@SpringBootApplication
@ClientCacheApplication
@EnableContinuousQueries
@EnableCachingDefinedRegions
@EnableEntityDefinedRegions
@EnableIndexing
@EnableGemfireCacheTransactions
@EnableGemfireCaching
@EnableGemfireFunctionExecutions
@EnableGemfireRepositories
@EnableClusterConfiguration
class ClientApplication { .. }

我們可以按關注點將此配置分解,如下所示

具有所有功能的 Spring ClientCache 應用程式
@SpringBootApplication
@Import({ GemFireConfiguration.class, CachingConfiguration.class,
    FunctionsConfiguration.class, QueriesConfiguration.class,
    RepositoriesConfiguration.class })
class ClientApplication { .. }

@ClientCacheApplication
@EnableClusterConfiguration
@EnableGemfireCacheTransactions
class GemFireConfiguration { .. }

@EnableGemfireCaching
@EnableCachingDefinedRegions
class CachingConfiguration { .. }

@EnableGemfireFunctionExecutions
class FunctionsConfiguration { .. }

@EnableContinuousQueries
class QueriesConfiguration {

   @ContinuousQuery(..)
   void processCqEvent(CqEvent event) {
       ...
   }
}

@EnableEntityDefinedRegions
@EnableGemfireRepositories
@EnableIndexing
class RepositoriesConfiguration { .. }

雖然這對於 Spring Framework 來說無關緊要,但我們通常建議以可讀性為目標,以方便下一個必須維護程式碼的人(這可能在未來的某個時候是您)。

6.18.2. 其他基於配置的註解

以下 SDG 註解未在本參考文件中討論,原因要麼是該註解支援 Pivotal GemFire 的已棄用功能,要麼是有更好的替代方法來完成該註解提供的功能

  • @EnableAuth:啟用 Pivotal GemFire 的舊身份驗證和授權安全模型。(已棄用。Pivotal GemFire 的新整合安全框架可以透過使用 SDG 的 @EnableSecurity 註解在客戶端和伺服器上啟用,如“配置安全性”中所述。)

  • @EnableAutoRegionLookup:不推薦。本質上,此註解支援查詢外部配置元資料(例如 cache.xml 或應用於伺服器時的叢集配置)中定義的 Region,並自動將這些 Region 註冊為 Spring 容器中的 bean。此註解對應於 SDG XML 名稱空間中的 <gfe:auto-region-lookup> 元素。更多詳細資訊可以在此處找到。使用者在使用 Spring 和 Spring Data for Pivotal GemFire 時通常應優先使用 Spring 配置。請改參見“配置 Region”和“配置叢集配置推送”。

  • @EnableBeanFactoryLocator:啟用 SDG GemfireBeanFactoryLocator 功能,僅在使用外部配置元資料(例如 cache.xml)時有用。例如,如果您在 cache.xml 中定義的 Region 上定義了 CacheLoader,您仍然可以使用 Spring 配置中定義的(例如)關係資料庫 DataSource bean 自動裝配此 CacheLoader。此註解利用了此 SDG 功能,如果您有大量遺留配置元資料,例如 cache.xml 檔案,則可能有用。

  • @EnableGemFireAsLastResource:在 全域性 - JTA 事務管理與 Pivotal GemFire 中討論。

  • @EnableMcast:啟用 Pivotal GemFire 的舊對等發現機制,該機制使用基於 UDP 的多播網路。(已棄用。請改用 Pivotal GemFire 定位器。請參見“配置嵌入式定位器”。

  • @EnableRegionDataAccessTracing:用於除錯目的。此註解透過註冊 AOP 切面來啟用對 Region 上執行的所有資料訪問操作的跟蹤,該切面代理 Spring 容器中宣告為 bean 的所有 Region,攔截 Region 操作並記錄事件。

6.19. 結論

正如我們在前面的章節中所瞭解到的,Spring Data for Pivotal GemFire 的新基於註解的配置模型提供了巨大的功能。希望它能實現其目標,讓您在使用 Pivotal GemFire 和 Spring 時更容易**快速輕鬆地入門**。

請記住,當您使用新註解時,您仍然可以使用 Java 配置或 XML 配置。您甚至可以透過在 Spring @Configuration@SpringBootApplication 類上使用 Spring 的 @Import@ImportResource 註解來組合所有三種方法。當您明確提供一個否則將由 Spring Data for Pivotal GemFire 使用其中一個註解提供的 bean 定義時,基於註解的配置就會退讓。

在某些情況下,您甚至可能需要回退到 Java 配置,就像在 Configurers 情況中一樣,以處理更復雜或條件配置邏輯,這些邏輯不容易用註解表達或無法單獨透過註解完成。請不要驚慌。這種行為是意料之中的。

例如,需要 Java 或 XML 配置的另一個情況是配置 Pivotal GemFire WAN 元件,目前這些元件沒有任何註解配置支援。但是,定義和註冊 WAN 元件只需要在 Spring @Configuration@SpringBootApplication 類的 Java 配置中使用 org.springframework.data.gemfire.wan.GatewayReceiverFactoryBeanorg.springframework.data.gemfire.wan.GatewaySenderFactoryBean API 類(推薦)。

註解並非旨在處理所有情況。註解旨在幫助您**儘可能快速輕鬆地啟動和執行**,尤其是在開發期間。

我們希望您會喜歡這些新功能!

6.20. 基於註解的配置快速入門

以下部分概述了 SDG 註解,以便快速入門。

所有註解都提供了額外的配置屬性以及相關的屬性,以便在執行時方便地自定義 Pivotal GemFire 的配置和行為。但是,通常,使用特定的 Pivotal GemFire 功能不需要任何屬性或相關屬性。只需宣告註解即可啟用該功能,然後就完成了。有關更多詳細資訊,請參閱每個註解的單獨 Javadoc。

6.20.1. 配置 ClientCache 應用程式

要配置和引導 Pivotal GemFire ClientCache 應用程式,請使用以下內容

@SpringBootApplication
@ClientCacheApplication
public class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }
}

有關更多詳細資訊,請參閱 使用 Spring 配置 Pivotal GemFire 應用程式

6.20.2. 配置對等 Cache 應用程式

要配置和引導 Pivotal GemFire 對等 Cache 應用程式,請使用以下內容

@SpringBootApplication
@PeerCacheApplication
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
如果您想啟用一個允許 ClientCache 應用程式連線到此伺服器的 CacheServer,那麼只需將 @PeerCacheApplication 註解替換為 @CacheServerApplication 註解。這將啟動一個在“localhost”上執行的 CacheServer,偵聽預設的 CacheServer40404

有關更多詳細資訊,請參閱 使用 Spring 配置 Pivotal GemFire 應用程式

6.20.3. 配置嵌入式定位器

使用 @EnableLocator 註解您的 Spring @PeerCacheApplication@CacheServerApplication 類,以啟動一個繫結到所有 NIC 的嵌入式定位器,偵聽預設的定位器埠 10334,如下所示

@SpringBootApplication
@CacheServerApplication
@EnableLocator
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
@EnableLocator 只能與 Pivotal GemFire 伺服器應用程式一起使用。

請參閱 @EnableLocator Javadoc

有關更多詳細資訊,請參閱 配置嵌入式定位器

6.20.4. 配置嵌入式管理器

使用 @EnableManager 註解您的 Spring @PeerCacheApplication@CacheServerApplication 類,以啟動一個繫結到所有 NIC 的嵌入式管理器,偵聽預設的管理器埠 1099,如下所示

@SpringBootApplication
@CacheServerApplication
@EnableManager
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
@EnableManager 只能與 Pivotal GemFire 伺服器應用程式一起使用。

請參閱 @EnableManager Javadoc

有關更多詳細資訊,請參閱 配置嵌入式管理器

6.20.5. 配置嵌入式 HTTP 伺服器

使用 @EnableHttpService 註解您的 Spring @PeerCacheApplication@CacheServerApplication 類,以啟動嵌入式 HTTP 伺服器 (Jetty),偵聽埠 7070,如下所示

@SpringBootApplication
@CacheServerApplication
@EnableHttpService
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
@EnableHttpService 只能與 Pivotal GemFire 伺服器應用程式一起使用。

有關更多詳細資訊,請參閱 配置嵌入式 HTTP 伺服器

6.20.6. 配置嵌入式 Memcached 伺服器

使用 @EnableMemcachedServer 註解您的 Spring @PeerCacheApplication@CacheServerApplication 類,以啟動嵌入式 Memcached 伺服器 (Gemcached),偵聽埠 11211,如下所示

@SpringBootApplication
@CacheServerApplication
@EnableMemcachedServer
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
@EnableMemcachedServer 只能與 Pivotal GemFire 伺服器應用程式一起使用。

有關更多詳細資訊,請參閱 配置嵌入式 Memcached 伺服器 (Gemcached)

6.20.7. 配置嵌入式 Redis 伺服器

使用 @EnableRedisServer 註解您的 Spring @PeerCacheApplication@CacheServerApplication 類,以啟動嵌入式 Redis 伺服器,偵聽埠 6379,如下所示

@SpringBootApplication
@CacheServerApplication
@EnableRedisServer
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
@EnableRedisServer 只能與 Pivotal GemFire 伺服器應用程式一起使用。
您必須在 Spring [Boot] 應用程式的類路徑中明確宣告 org.apache.geode:geode-redis 模組。

有關更多詳細資訊,請參閱 配置嵌入式 Redis 伺服器

6.20.8. 配置日誌記錄

要配置或調整 Pivotal GemFire 日誌記錄,請使用 @EnableLogging 註解您的 Spring、Pivotal GemFire 客戶端或伺服器應用程式類,如下所示

@SpringBootApplication
@ClientCacheApplication
@EnableLogging(logLevel="trace")
public class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }
}
預設的 log-level 是“config”。此外,此註解不會調整應用程式中的日誌級別,只會調整 Pivotal GemFire 的日誌級別。

請參閱 @EnableLogging Javadoc

有關更多詳細資訊,請參閱 配置日誌記錄

6.20.9. 配置統計資訊

要在執行時收集 Pivotal GemFire 統計資訊,請使用 @EnableStatistics 註解您的 Spring、Pivotal GemFire 客戶端或伺服器應用程式類,如下所示

@SpringBootApplication
@ClientCacheApplication
@EnableStatistics
public class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }
}

有關更多詳細資訊,請參閱 配置統計資訊

6.20.10. 配置 PDX

要啟用 Pivotal GemFire PDX 序列化,請使用 @EnablePdx 註解您的 Spring、Pivotal GemFire 客戶端或伺服器應用程式類,如下所示

@SpringBootApplication
@ClientCacheApplication
@EnablePdx
public class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }
}
Pivotal GemFire PDX 序列化是 Java 序列化的替代方案,具有許多附加優點。其中之一是,它使得您的所有應用程式域模型型別可序列化變得輕而易舉,而無需實現 java.io.Serializable
預設情況下,SDG 配置 MappingPdxSerializer 來序列化您的應用程式域模型型別,這不需要任何特殊的開箱即用配置即可正確識別需要序列化的應用程式域物件,然後執行序列化,因為 MappingPdxSerializer 中的邏輯基於 Spring Data 的對映基礎設施。有關更多詳細資訊,請參閱 MappingPdxSerializer

請參閱 @EnablePdx Javadoc

有關更多詳細資訊,請參閱 配置 PDX

6.20.11. 配置 SSL

要啟用 Pivotal GemFire SSL,請使用 @EnableSsl 註解您的 Spring、Pivotal GemFire 客戶端或伺服器應用程式類,如下所示

@SpringBootApplication
@ClientCacheApplication
@EnableSsl(components = SERVER)
public class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }
}
Pivotal GemFire 最少要求您使用適當的配置屬性或屬性指定金鑰庫和信任庫。金鑰庫和信任庫配置屬性或屬性都可以引用相同的 KeyStore 檔案。此外,如果檔案已加密,您將需要指定使用者名稱和密碼來訪問 KeyStore 檔案。
Pivotal GemFire SSL 允許您配置需要 TLS 的系統特定元件,例如客戶端/伺服器、定位器、閘道器等。您可以選擇指定 Pivotal GemFire 的所有元件都使用 SSL,方法是使用“ALL”。

請參閱 @EnableSsl Javadoc

有關更多詳細資訊,請參閱 配置 SSL

6.20.12. 配置安全性

要啟用 Pivotal GemFire 安全性,請使用 @EnableSecurity 註解您的 Spring、Pivotal GemFire 客戶端或伺服器應用程式類,如下所示

@SpringBootApplication
@ClientCacheApplication
@EnableSecurity
public class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }
}
在伺服器上,您必須配置對身份驗證憑據的訪問。您可以實現 Pivotal GemFire SecurityManager 介面,或宣告一個或多個 Apache Shiro Realms。有關更多詳細資訊,請參閱 配置伺服器安全性
在客戶端上,您必須配置使用者名稱和密碼。有關更多詳細資訊,請參閱 配置客戶端安全性

有關更多詳細資訊,請參閱 配置安全性

6.20.13. 配置 Pivotal GemFire 屬性

要配置功能導向的 SDG 配置註解未涵蓋的其他低階 Pivotal GemFire 屬性,請使用 @GemFireProperties 註解您的 Spring、Pivotal GemFire 客戶端或伺服器應用程式類,如下所示

@SpringBootApplication
@PeerCacheApplication
@EnableGemFireProperties(
    cacheXmlFile = "/path/to/cache.xml",
    conserveSockets = true,
    groups = "GroupOne",
    remoteLocators = "lunchbox[11235],mailbox[10101],skullbox[12480]"
)
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
某些 Pivotal GemFire 屬性僅限於客戶端,而其他屬性僅限於伺服器端。請查閱 Pivotal GemFire 文件以瞭解每個屬性的正確用法。

有關更多詳細資訊,請參閱 配置 Pivotal GemFire 屬性

6.20.14. 配置快取

要將 Pivotal GemFire 用作 Spring 快取抽象中的**快取提供程式**,並讓 SDG 自動為應用程式服務元件所需的快取建立 Pivotal GemFire Region,請使用 @EnableGemfireCaching@EnableCachingDefinedRegions 註解您的 Spring、Pivotal GemFire 客戶端或伺服器應用程式類,如下所示

@SpringBootApplication
@ClientCacheApplication
@EnableCachingDefinedRegions
@EnableGemfireCaching
public class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }
}

然後,只需繼續定義需要快取的應用程式服務,如下所示

@Service
public class BookService {

    @Cacheable("Books")
    public Book findBy(ISBN isbn) {
        ...
    }
}
@EnableCachingDefinedRegions 是可選的。也就是說,如果您願意,可以手動定義您的 Region。

有關更多詳細資訊,請參閱 配置 Spring 的快取抽象

6.20.15. 為持久化應用程式配置 Region、索引、儲存庫和實體

為了輕鬆建立 Spring、Pivotal GemFire 持久化客戶端或伺服器應用程式,請使用 @EnableEntityDefinedRegions@EnableGemfireRepositories@EnableIndexing 註解您的應用程式類,如下所示

@SpringBootApplication
@ClientCacheApplication
@EnableEntityDefinedRegions(basePackageClasses = Book.class)
@EnableGemfireRepositories(basePackageClasses = BookRepository.class)
@EnableIndexing
public class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }
}
使用 @EnableIndexing 註解時,@EnableEntityDefinedRegions 註解是必需的。有關更多詳細資訊,請參閱 配置索引

接下來,定義您的實體類並使用 @Region 對映註解來指定儲存您的實體的 Region。使用 @Indexed 註解來定義應用程式查詢中使用的實體欄位上的索引,如下所示

package example.app.model;

import ...;

@Region("Books")
public class Book {

  @Id
  private ISBN isbn;

  @Indexed;
  private Author author;

  @Indexed
  private LocalDate published;

  @LuceneIndexed
  private String title;

}
@Region("Books") 實體類註解由 @EnableEntityDefinedRegions 用於確定應用程式所需的 Region。有關更多詳細資訊,請參閱 配置特定型別的 RegionPOJO 對映

最後,定義您的 CRUD 儲存庫,其中包含簡單的查詢以持久化和訪問 Books,如下所示

package example.app.repo;

import ...;

public interface BookRepository extends CrudRepository {

  List<Book> findByAuthorOrderByPublishedDesc(Author author);

}
有關更多詳細資訊,請參閱 Spring Data for Pivotal GemFire 儲存庫

請參閱 @Region Javadoc

請參閱 @Indexed Javadoc

請參閱 @LuceneIndexed Javadoc

有關更多詳細資訊,請參閱 配置 Region

有關更多詳細資訊,請參閱 Spring Data for Pivotal GemFire 儲存庫

6.20.16. 從叢集定義的 Region 配置客戶端 Region

或者,您可以使用 @EnableClusterDefinedRegions 從叢集中已定義的 Region 定義客戶端 [*PROXY] Region,如下所示

@SpringBootApplication
@ClientCacheApplication
@EnableClusterDefinedRegions
@EnableGemfireRepositories
public class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }

  ...
}

有關更多詳細資訊,請參閱 配置叢集定義的 Region

6.20.17. 配置函式

Pivotal GemFire 函式在分散式計算場景中很有用,在這種場景中,需要資料的可能昂貴的計算可以在叢集中的節點之間並行執行。在這種情況下,將邏輯帶到資料所在(儲存)的位置比請求和獲取資料由計算處理更有效。

結合 @EnableGemfireFunctions@GemfireFunction 註解,啟用以 POJO 方法實現 Pivotal GemFire 函式定義,如下所示

@PeerCacheApplication
@EnableGemfireFunctions
class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }

  @GemfireFunction
  Integer computeLoyaltyPoints(Customer customer) {
    ...
  }
}

結合 @EnableGemfireFunctionExecutions 和以下函式呼叫註解之一:@OnMember@OnMembers@OnRegion@OnServer@OnServers

@ClientCacheApplication
@EnableGemfireFunctionExecutions(basePackageClasses = CustomerRewardsFunction.class)
class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }
}

@OnRegion("Customers")
interface CustomerRewardsFunctions {

  Integer computeLoyaltyPoints(Customer customer);

}

有關更多詳細資訊,請參閱 函式執行的註解支援

6.20.18. 配置連續查詢

即時事件流處理對於資料密集型應用程式來說變得越來越重要,主要是為了及時響應使用者請求。Pivotal GemFire 連續查詢 (CQ) 將幫助您輕鬆實現這項相當複雜的任務。

透過使用 @EnableContinuousQueries 註解您的應用程式類來啟用 CQ,並定義您的 CQ 以及相關的事件處理器,如下所示

@ClientCacheApplication
@EnableContinuousQueries
class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }
}

然後,透過使用 @ContinousQuery 註解相關的處理器方法來定義您的 CQ,如下所示

@Service
class CustomerService {

  @ContinuousQuery(name = "CustomerQuery", query = "SELECT * FROM /Customers c WHERE ...")
  public void process(CqEvent event) {
    ...
  }
}

每當發生事件改變 Customer 資料以匹配您的連續 OQL 查詢 (CQ) 中的謂詞時,process 方法將被呼叫。

Pivotal GemFire CQ 僅是客戶端功能。

有關更多詳細資訊,請參閱 連續查詢 (CQ)配置連續查詢

6.20.19. 配置叢集配置

在使用 Pivotal GemFire 作為 Pivotal GemFire ClientCache 應用程式開發 Spring Data 應用程式時,在開發期間配置伺服器以匹配客戶端/伺服器拓撲中的客戶端非常有用。事實上,Pivotal GemFire 期望當您在客戶端上有一個 "/Example" PROXY Region 時,叢集中存在一個名稱匹配的 Region(即 "Example")。

您可以使用 Gfsh 建立應用程式所需的所有 Region 和索引,或者,您可以在執行 Spring Data 應用程式時,將開發 Spring Data 應用程式時已表達的配置元資料推送出去。

這就像使用 @EnableClusterConfiguration(..) 註解您的主應用程式類一樣簡單。

使用 @EnableClusterConfiguration
@ClientCacheApplication
@EnableClusterConfiguration(useHttp = true)
class ClientApplication {
  ...
}
大多數情況下,在使用客戶端/伺服器拓撲時,尤其是在生產環境中,叢集的伺服器將使用 Gfsh 啟動。在這種情況下,通常使用 HTTP(S) 將配置元資料(例如 Region 和 Index 定義)傳送到叢集。當使用 HTTP 時,配置元資料會發送到叢集中的管理器,並一致地分佈到叢集中的伺服器節點。
要使用 @EnableClusterConfiguration,您必須在 Spring 應用程式類路徑中宣告 org.springframework:spring-web 依賴項。

有關更多詳細資訊,請參閱 配置叢集配置推送

6.20.20. 配置 GatewayReceivers

不同 Pivotal GemFire 叢集之間的資料複製是一種日益重要的容錯和高可用性 (HA) 機制。Pivotal GemFire WAN 複製是一種機制,允許一個 Pivotal GemFire 叢集以可靠和容錯的方式將其資料複製到另一個 Pivotal GemFire 叢集。

Pivotal GemFire WAN 複製需要配置兩個元件

  • GatewayReceiver - 接收來自遠端 Pivotal GemFire 叢集的 GatewaySender 資料的 WAN 複製元件。

  • GatewaySender - 將資料傳送到遠端 Pivotal GemFire 叢集的 GatewayReceiver 的 WAN 複製元件。

要啟用 GatewayReceiver,應用程式類需要使用 @EnableGatewayReceiver 註解,如下所示

@CacheServerApplication
@EnableGatewayReceiver(manualStart = false, startPort = 10000, endPort = 11000, maximumTimeBetweenPings = 1000,
    socketBufferSize = 16384, bindAddress = "localhost",transportFilters = {"transportBean1", "transportBean2"},
    hostnameForSenders = "hostnameLocalhost"){
      ...
      ...
    }
}
class MySpringApplication { .. }
Pivotal GemFire GatewayReceiver 僅是伺服器端功能,只能在 CacheServer 或對等 Cache 節點上配置。

6.20.21. 配置 GatewaySenders

要啟用 GatewaySender,應用程式類需要使用 @EnableGatewaySenders@EnableGatewaySender 註解,如下所示

@CacheServerApplication
@EnableGatewaySenders(gatewaySenders = {
		@EnableGatewaySender(name = "GatewaySender", manualStart = true,
			remoteDistributedSystemId = 2, diskSynchronous = true, batchConflationEnabled = true,
			parallel = true, persistent = false,diskStoreReference = "someDiskStore",
			orderPolicy = OrderPolicyType.PARTITION, alertThreshold = 1234, batchSize = 100,
			eventFilters = "SomeEventFilter", batchTimeInterval = 2000, dispatcherThreads = 22,
			maximumQueueMemory = 400,socketBufferSize = 16384,
			socketReadTimeout = 4000, regions = { "Region1"}),
		@EnableGatewaySender(name = "GatewaySender2", manualStart = true,
			remoteDistributedSystemId = 2, diskSynchronous = true, batchConflationEnabled = true,
			parallel = true, persistent = false, diskStoreReference = "someDiskStore",
			orderPolicy = OrderPolicyType.PARTITION, alertThreshold = 1234, batchSize = 100,
			eventFilters = "SomeEventFilter", batchTimeInterval = 2000, dispatcherThreads = 22,
			maximumQueueMemory = 400, socketBufferSize = 16384,socketReadTimeout = 4000,
			regions = { "Region2" })
}){
class MySpringApplication { .. }
}
Pivotal GemFire GatewaySender 僅是伺服器端功能,只能在 CacheServer 或對等 Cache 節點上配置。

在上面的示例中,應用程式配置了兩個 Region,Region1Region2。此外,將配置兩個 GatewaySender 來服務這兩個 Region。GatewaySender1 將配置為複製 Region1 的資料,GatewaySender2 將配置為複製 Region2 的資料。

如所示,每個 GatewaySender 屬性都可以在每個 EnableGatewaySender 註解上配置。

也可以採用更通用的“預設”屬性方法,其中所有屬性都在 EnableGatewaySenders 註解上配置。這樣,一組通用的預設值可以在父註解上設定,然後如果需要,可以在子註解上覆蓋,如下所示

@CacheServerApplication
@EnableGatewaySenders(gatewaySenders = {
		@EnableGatewaySender(name = "GatewaySender", transportFilters = "transportBean1", regions = "Region2"),
		@EnableGatewaySender(name = "GatewaySender2")},
		manualStart = true, remoteDistributedSystemId = 2,
		diskSynchronous = false, batchConflationEnabled = true, parallel = true, persistent = true,
		diskStoreReference = "someDiskStore", orderPolicy = OrderPolicyType.PARTITION, alertThreshold = 1234, batchSize = 1002,
		eventFilters = "SomeEventFilter", batchTimeInterval = 2000, dispatcherThreads = 22, maximumQueueMemory = 400,
		socketBufferSize = 16384, socketReadTimeout = 4000, regions = { "Region1", "Region2" },
		transportFilters = { "transportBean2", "transportBean1" })
class MySpringApplication { .. }
regions 屬性留空或未填充時,GatewaySender 將自動附加到應用程式中的每個已配置 Region

7. 使用 Pivotal GemFire API

一旦配置了 Pivotal GemFire 快取和 Region,它們就可以注入並在應用程式物件中使用。本章描述了與 Spring 的事務管理功能和 DAO 異常層次結構的整合。本章還涵蓋了對 Pivotal GemFire 管理物件的依賴注入支援。

7.1. GemfireTemplate

與 Spring 提供的許多其他高階抽象一樣,Spring Data for Pivotal GemFire 提供了一個**模板**來簡化 Pivotal GemFire 資料訪問操作。該類提供了幾個包含常見 Region 操作的方法,但還提供了透過使用 GemfireCallback 在不處理 Pivotal GemFire 檢查異常的情況下對本機 Pivotal GemFire API 執行程式碼的功能。

模板類需要一個 Pivotal GemFire Region,一旦配置,它是執行緒安全的,並且可以在多個應用程式類中重用

<bean id="gemfireTemplate" class="org.springframework.data.gemfire.GemfireTemplate" p:region-ref="SomeRegion"/>

一旦配置了模板,開發人員就可以將其與 GemfireCallback 一起使用,直接與 Pivotal GemFire Region 互動,而無需處理檢查異常、執行緒或資源管理問題。

template.execute(new GemfireCallback<Iterable<String>>() {

	public Iterable<String> doInGemfire(Region region)
	        throws GemFireCheckedException, GemFireException {

		Region<String, String> localRegion = (Region<String, String>) region;

		localRegion.put("1", "one");
		localRegion.put("3", "three");

		return localRegion.query("length < 5");
	}
});

為了充分發揮 Pivotal GemFire 查詢語言的強大功能,開發人員可以使用 findfindUnique 方法,與 query 方法相比,它們可以跨多個 Region 執行查詢、執行投影等。

當查詢選擇多個專案(透過 SelectResults)時,應使用 find 方法,而後者 findUnique,顧名思義,當只返回一個物件時使用。

7.2. 異常轉換

使用新的資料訪問技術不僅需要適應新的 API,還需要處理該技術特有的異常。

為了適應異常處理情況,*Spring Framework* 提供了一個與技術無關且一致的 異常層次結構,它將應用程式從專有且通常是“檢查型”異常抽象為一組集中的執行時異常。

正如 *Spring Framework* 文件中提到的,異常轉換可以透過使用 @Repository 註解和 AOP,透過定義 PersistenceExceptionTranslationPostProcessor bean 透明地應用於您的資料訪問物件 (DAO)。當使用 Pivotal GemFire 時,只要聲明瞭 CacheFactoryBean(例如,使用 <gfe:cache/><gfe:client-cache> 宣告),就會啟用相同的異常轉換功能,該 CacheFactoryBean 充當異常轉換器,並由 Spring 基礎設施自動檢測和相應使用。

7.3. 本地快取事務管理

*Spring Framework* 最受歡迎的功能之一是 事務管理

如果您不熟悉 Spring 的事務抽象,那麼我們強烈建議您閱讀有關 *Spring 事務管理* 基礎設施的內容,因為它提供了一個一致的*程式設計模型*,該模型透明地跨多個 API 工作,並且可以透過程式設計或宣告方式進行配置(最受歡迎的選擇)。

對於 Pivotal GemFire,Spring Data for Pivotal GemFire 提供了一個專用的、每個快取的 PlatformTransactionManager,一旦宣告,它允許透過 Spring 以原子方式執行 Region 操作。

使用 XML 啟用事務管理
<gfe:transaction-manager id="txManager" cache-ref="myCache"/>
如果 Pivotal GemFire 快取以預設名稱 gemfireCache 定義,則可以透過刪除 cache-ref 屬性進一步簡化上面的示例。與其他 Spring Data for Pivotal GemFire 名稱空間元素一樣,如果未配置快取 bean 名稱,則將使用上述命名約定。此外,如果未明確指定事務管理器名稱,則事務管理器名稱為“gemfireTransactionManager”。

目前,Pivotal GemFire 支援帶有**讀已提交**隔離的樂觀事務。此外,為了保證此隔離,開發人員應避免進行手動修改快取中值的**原地**更改。為防止這種情況發生,事務管理器預設將快取配置為使用**讀時複製**語義,這意味著每次執行讀取時都會建立實際值的克隆。如果需要,可以透過 copyOnRead 屬性停用此行為。

由於在啟用**讀時複製**時會為給定鍵的值建立副本,因此您必須隨後呼叫 Region.put(key, value) 才能以事務方式更新值。

有關底層 Geode 事務管理器的語義和行為的更多資訊,請參閱 Geode CacheTransactionManager Javadoc 以及 文件

7.4. 全域性 JTA 事務管理

Pivotal GemFire 也可以參與基於全域性 JTA 的事務,例如由 Java EE 應用程式伺服器(例如 WebSphere Application Server (WAS))使用容器管理事務 (CMT) 以及其他 JTA 資源管理的事務。

然而,與許多其他 JTA“相容”資源(例如 ActiveMQ 等 JMS 訊息代理)不同,Pivotal GemFire **不是** XA 相容資源。因此,Pivotal GemFire 必須在 JTA 事務中定位為“*最後資源*”(*準備階段*),因為它不實現兩階段提交協議,或者更確切地說不處理分散式事務。

許多支援CMT的託管環境都支援JTA事務中的“Last Resource”(不符合XA規範的資源),儘管JTA規範中並未實際要求。有關不符合XA規範的“Last Resource”的含義,請參閱Red Hat的文件。事實上,Red Hat的JBoss專案Narayana就是這樣一個LGPL開源實現。Narayana將其稱為“Last Resource Commit Optimization”(LRCO)。更多詳情請參見此處

然而,無論您是在獨立環境中使用支援“Last Resource”的開源JTA事務管理實現來使用Pivotal GemFire,還是在託管環境(例如Java EE AS,如WAS)中使用,Spring Data for Pivotal GemFire都能滿足您的需求。

在涉及多個事務資源的JTA事務中,您必須完成一系列步驟才能正確地將Pivotal GemFire用作“Last Resource”。此外,在這種配置中,只能有一個不符合XA規範的資源(例如Pivotal GemFire)。

1) 首先,您必須完成Pivotal GemFire文件此處的步驟1-4。

上述#1獨立於您的Spring [Boot]和/或[Data for Pivotal GemFire]應用程式,並且必須成功完成。

2) 參考Pivotal GemFire文件中的步驟5,當使用@EnableGemFireAsLastResource註解時,Spring Data for Pivotal GemFire的註解支援將嘗試為您設定GemFireCachecopyOnRead屬性。

但是,如果SDG的自動配置在這方面不成功,那麼您必須在<gfe:cache><gfe:client-cache> XML元素中顯式設定copy-on-read屬性,或者在JavaConfig中將CacheFactoryBean類的copyOnRead屬性設定為true。例如

ClientCache XML

使用XML設定copy-on-read(客戶端)
<gfe:client-cache ... copy-on-read="true"/>

ClientCache JavaConfig

使用JavaConfig設定copyOnRead(客戶端)
@Bean
ClientCacheFactoryBean gemfireCache() {

  ClientCacheFactoryBean gemfireCache = new ClientCacheFactoryBean();

  gemfireCache.setCopyOnRead(true);

  return gemfireCache;
}

Peer Cache XML

使用XML設定copy-on-read(伺服器)
<gfe:cache ... copy-on-read="true"/>

Peer Cache JavaConfig

使用JavaConfig設定copyOnRead(伺服器)
@Bean
CacheFactoryBean gemfireCache() {

  CacheFactoryBean gemfireCache = new CacheFactoryBean();

  gemfireCache.setCopyOnRead(true);

  return gemfireCache;
}
顯式設定copy-on-read屬性或copyOnRead屬性實際上沒有必要。啟用事務管理會自動處理讀取時的複製。

3) 此時,您跳過Pivotal GemFire文件中的步驟6-8,讓Spring Data Geode發揮其魔力。您所需要做的就是使用Spring Data for Pivotal GemFire@EnableGemFireAsLastResource註解來註解您的Spring @Configuration類,Spring的事務管理基礎設施和Spring Data for Pivotal GemFire的@EnableGemFireAsLastResource註解配置的組合就能實現這一點。

配置如下……​

@Configuration
@EnableGemFireAsLastResource
@EnableTransactionManagement(order = 1)
class GeodeConfiguration {
  ...
}

唯一的要求是……​

3.1) @EnableGemFireAsLastResource註解必須與Spring的@EnableTransactionManagement註解在同一個Spring @Configuration類上宣告。

3.2) @EnableTransactionManagement註解的order屬性必須顯式設定為非Integer.MAX_VALUEInteger.MIN_VALUE的整數值(預設為Integer.MAX_VALUE)。

當然,希望您知道在使用JTA事務時,您還需要像這樣配置Spring的JtaTransactionManager

@Bean
public JtaTransactionManager transactionManager(UserTransaction userTransaction) {

   JtaTransactionManager transactionManager = new JtaTransactionManager();

   transactionManager.setUserTransaction(userTransaction);

   return transactionManager;
}
本地快取事務管理一節中的配置適用於此處。Spring Data for Pivotal GemFire的GemfireTransactionManager僅適用於“本地專用”快取事務,適用於“全域性”JTA事務。因此,在這種情況下,您配置SDG GemfireTransactionManager。您如上所示配置Spring的JtaTransactionManager

有關使用Spring事務管理與JTA的更多詳情,請參見此處

實際上,Spring Data for Pivotal GemFire的@EnableGemFireAsLastResource註解匯入的配置包含兩個Aspect bean定義,它們在事務操作的適當點處理Pivotal GemFire o.a.g.ra.GFConnectionFactory.getConnection()o.a.g.ra.GFConnection.close()操作。

具體來說,正確的事件順序如下:

  1. jtaTransation.begin()

  2. GFConnectionFactory.getConnection()

  3. 呼叫應用程式的@Transactional服務方法

  4. jtaTransaction.commit()jtaTransaction.rollback()

  5. 最後,GFConnection.close()

這與您作為應用程式開發人員,如果必須手動使用JTA API + Pivotal GemFire API時,會如何編寫程式碼是一致的,如Pivotal GemFire示例所示。

謝天謝地,Spring為您完成了繁重的工作,您在應用適當的配置(如上所示)後所需要做的就是:

將服務方法宣告為@Transactional
@Service
class MyTransactionalService {

  @Transactional
  public <Return-Type> someTransactionalServiceMethod() {
    // perform business logic interacting with and accessing multiple JTA resources atomically
  }

  ...
}

一旦您的應用程式進入@Transactional邊界(即呼叫MyTransactionService.someTransactionalServiceMethod()時),上述#1和#4就會由Spring基於JTA的PlatformTransactionManager為您妥善處理。

#2和#3由Spring Data for Pivotal GemFire透過@EnableGemFireAsLastResource註解啟用的新Aspects處理。

#3當然是您的應用程式的責任。

事實上,配置適當的日誌後,您將看到正確的事件順序……​

事務日誌輸出
2017-Jun-22 11:11:37 TRACE TransactionInterceptor - Getting transaction for [example.app.service.MessageService.send]

2017-Jun-22 11:11:37 TRACE GemFireAsLastResourceConnectionAcquiringAspect - Acquiring {data-store-name} Connection
from {data-store-name} JCA ResourceAdapter registered at [gfe/jca]

2017-Jun-22 11:11:37 TRACE MessageService - PRODUCER [ Message :
[{ @type = example.app.domain.Message, id= MSG0000000000, message = SENT }],
JSON : [{"id":"MSG0000000000","message":"SENT"}] ]

2017-Jun-22 11:11:37 TRACE TransactionInterceptor - Completing transaction for [example.app.service.MessageService.send]

2017-Jun-22 11:11:37 TRACE GemFireAsLastResourceConnectionClosingAspect - Closed {data-store-name} Connection @ [Reference [...]]

有關使用Pivotal GemFire快取級別事務的更多詳情,請參見此處

有關在JTA事務中使用Pivotal GemFire的更多詳情,請參見此處

有關將Pivotal GemFire配置為“Last Resource”的更多詳情,請參見此處

7.5. TransactionEventListener

在使用事務時,可能希望註冊一個監聽器以在事務提交之前或之後執行某些操作,或者在回滾發生後執行某些操作。

Spring Data for Pivotal GemFire透過@TransactionalEventListener註解,使得建立將在事務特定階段呼叫的監聽器變得容易。用@TransactionalEventListener註解的方法(如下所示)將在指定的phase中,收到從事務方法釋出事件的通知。

事務提交後事件監聽器
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(MyEvent event) {
    // do something after transaction is committed
}

為了呼叫上述方法,您必須在事務中釋出一個事件,如下所示:

釋出事務事件
@Service
class MyTransactionalService {

  @Autowired
  private final ApplicationEventPublisher applicationEventPublisher;

  @Transactional
  public <Return-Type> someTransactionalServiceMethod() {

    // Perform business logic interacting with and accessing multiple transactional resources atomically, then...

    applicationEventPublisher.publishEvent(new MyEvent(...));
  }

  ...
}

@TransactionalEventListener註解允許您指定事件處理方法將被呼叫的事務phase。選項包括:AFTER_COMMITAFTER_COMPLETIONAFTER_ROLLBACKBEFORE_COMMIT。如果未指定,phase預設為AFTER_COMMIT。如果您希望即使沒有事務存在也呼叫監聽器,您可以將fallbackExecution設定為true

7.6. 持續查詢 (CQ)

Pivotal GemFire提供的一個強大功能是持續查詢(或CQ)。

簡而言之,CQ允許開發人員建立和註冊一個OQL查詢,然後在Pivotal GemFire中新增的新資料與查詢謂詞匹配時自動收到通知。Spring Data for Pivotal GemFire透過org.springframework.data.gemfire.listener包及其監聽器容器為CQ提供了專門的支援;其功能和命名與Spring Framework中的JMS整合非常相似;事實上,熟悉Spring中JMS支援的使用者應該會感到非常適應。

基本上,Spring Data for Pivotal GemFire允許POJO上的方法成為CQ的端點。只需定義查詢並指示當匹配發生時應呼叫的方法。Spring Data for Pivotal GemFire會處理其餘部分。這與Java EE的訊息驅動Bean樣式非常相似,但沒有任何對基類或介面實現的要求,並且基於Pivotal GemFire。

目前,持續查詢僅支援Pivotal GemFire的客戶端/伺服器拓撲。此外,使用的客戶端池需要啟用訂閱。更多資訊請參閱Pivotal GemFire文件

7.6.1. 持續查詢監聽器容器

Spring Data for Pivotal GemFire透過使用SDG的ContinuousQueryListenerContainer簡化了CQ事件的建立、註冊、生命週期和分派,它為使用者完成了所有繁重的工作。熟悉EJB和JMS的使用者應該會發現這些概念很熟悉,因為它被設計得儘可能接近Spring Framework中其訊息驅動POJO(MDP)提供的支援。

SDG ContinuousQueryListenerContainer充當事件(或訊息)監聽器容器;它用於接收來自已註冊CQ的事件,並呼叫注入其中的POJO。監聽器容器負責所有訊息接收的執行緒處理以及分派到監聽器進行處理。它充當EDP(事件驅動POJO)和事件提供者之間的中介,並負責CQ的建立和註冊(以接收事件)、資源獲取和釋放、異常轉換等。這使您作為應用程式開發人員,能夠編寫與接收事件(並對其作出反應)相關的(可能複雜的)業務邏輯,並將樣板Pivotal GemFire基礎設施關注點委託給框架。

監聽器容器是完全可定製的。開發人員可以選擇使用CQ執行緒執行分派(同步交付),或者透過定義合適的java.util.concurrent.Executor(或Spring的TaskExecutor)使用新執行緒(來自現有池)進行非同步方法。根據負載、監聽器數量或執行時環境,開發人員應更改或調整執行器以更好地滿足其需求。特別是,在託管環境(例如應用程式伺服器)中,強烈建議選擇合適的TaskExecutor以利用其執行時。

7.6.2. ContinuousQueryListenerContinuousQueryListenerAdapter

ContinuousQueryListenerAdapter類是Spring Data for Pivotal GemFire CQ支援中的最終元件。簡而言之,該類允許您以最小的限制將幾乎任何實現類公開為EDP。ContinuousQueryListenerAdapter實現了ContinuousQueryListener介面,這是一個簡單的監聽器介面,類似於Pivotal GemFire的CqListener

考慮以下介面定義。注意各種事件處理方法及其引數:

public interface EventDelegate {
     void handleEvent(CqEvent event);
     void handleEvent(Operation baseOp);
     void handleEvent(Object key);
     void handleEvent(Object key, Object newValue);
     void handleEvent(Throwable throwable);
     void handleQuery(CqQuery cq);
     void handleEvent(CqEvent event, Operation baseOp, byte[] deltaValue);
     void handleEvent(CqEvent event, Operation baseOp, Operation queryOp, Object key, Object newValue);
}
package example;

class DefaultEventDelegate implements EventDelegate {
    // implementation elided for clarity...
}

特別要注意的是,EventDelegate介面的上述實現完全沒有Pivotal GemFire依賴項。它確實是一個POJO,我們可以並且將透過以下配置將其轉換為EDP。

該類不必實現介面;介面僅用於更好地展示契約與實現之間的解耦。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:gfe="https://www.springframework.org/schema/gemfire"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    https://www.springframework.org/schema/gemfire https://www.springframework.org/schema/gemfire/spring-gemfire.xsd
">

	<gfe:client-cache/>

	<gfe:pool subscription-enabled="true">
	   <gfe:server host="localhost" port="40404"/>
	</gfe:pool>

	<gfe:cq-listener-container>
	   <!-- default handle method -->
	   <gfe:listener ref="listener" query="SELECT * FROM /SomeRegion"/>
	   <gfe:listener ref="another-listener" query="SELECT * FROM /AnotherRegion" name="myQuery" method="handleQuery"/>
	</gfe:cq-listener-container>

	<bean id="listener" class="example.DefaultMessageDelegate"/>
	<bean id="another-listener" class="example.DefaultMessageDelegate"/>
  ...
<beans>
上面的示例展示了監聽器可以具有的各種形式;至少需要監聽器引用和實際查詢定義。但是,可以為生成的持續查詢指定名稱(對監控很有用),也可以指定方法的名稱(預設為handleEvent)。指定的方法可以具有各種引數型別,EventDelegate介面列出了允許的型別。

上面的示例使用Spring Data for Pivotal GemFire名稱空間來宣告事件監聽器容器並自動註冊監聽器。完整的bean定義如下所示:

<!-- this is the Event Driven POJO (MDP) -->
<bean id="eventListener" class="org.springframework.data.gemfire.listener.adapter.ContinuousQueryListenerAdapter">
    <constructor-arg>
        <bean class="gemfireexample.DefaultEventDelegate"/>
    </constructor-arg>
</bean>

<!-- and this is the event listener container... -->
<bean id="gemfireListenerContainer" class="org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer">
    <property name="cache" ref="gemfireCache"/>
    <property name="queryListeners">
      <!-- set of CQ listeners -->
      <set>
        <bean class="org.springframework.data.gemfire.listener.ContinuousQueryDefinition" >
               <constructor-arg value="SELECT * FROM /SomeRegion" />
               <constructor-arg ref="eventListener"/>
        </bean>
      </set>
    </property>
</bean>

每次收到事件時,介面卡都會在Pivotal GemFire事件和所需方法引數之間自動透明地執行型別轉換。由方法呼叫引起的任何異常都會被容器捕獲和處理(預設情況下會記錄日誌)。

7.7. 連線Declarable元件

Pivotal GemFire XML配置(通常稱為cache.xml)允許使用者物件作為配置的一部分進行宣告。通常,這些物件是CacheLoaders或Pivotal GemFire支援的其他可插入回撥元件。使用原生的Pivotal GemFire配置,透過XML宣告的每個使用者型別都必須實現Declarable介面,該介面允許透過Properties例項將任意引數傳遞給宣告的類。

在本節中,我們描述瞭如何在cache.xml中定義這些可插入元件時使用Spring進行配置,同時將您的快取/區域配置定義在cache.xml中。這使得您的可插入元件可以專注於應用程式邏輯,而不是DataSources或其他協作者的位置或建立。

但是,如果您正在啟動一個全新的專案,建議您直接在Spring中配置Cache、Region和其他可插入的Pivotal GemFire元件。這避免了從Declarable介面或本節中介紹的基類繼承。

有關此方法的更多資訊,請參見以下側邊欄。

消除Declarable元件

開發人員可以完全透過Spring配置自定義型別,如配置區域中所述。這樣,開發人員不必實現Declarable介面,並且還可以從Spring IoC容器的所有功能中受益(不僅是依賴注入,還有生命週期和例項管理)。

作為使用Spring配置Declarable元件的示例,考慮以下宣告(取自DeclarableJavadoc):

<cache-loader>
   <class-name>com.company.app.DBLoader</class-name>
   <parameter name="URL">
     <string>jdbc://12.34.56.78/mydb</string>
   </parameter>
</cache-loader>

為了簡化解析、轉換引數和初始化物件的工作,Spring Data for Pivotal GemFire提供了一個基類(WiringDeclarableSupport),它允許Pivotal GemFire使用者物件透過模板bean定義進行連線,或者在缺少模板的情況下,透過Spring IoC容器執行自動連線。為了利用此功能,使用者物件需要擴充套件WiringDeclarableSupport,它會自動定位宣告的BeanFactory並在初始化過程中執行連線。

為什麼需要基類?

在當前的Pivotal GemFire版本中,沒有物件工廠的概念,宣告的型別是例項化並直接使用的。換句話說,沒有簡單的方法可以在Pivotal GemFire之外管理物件的建立。

7.7.1. 使用模板bean定義進行配置

使用時,WiringDeclarableSupport會首先嚐試定位現有的bean定義並將其用作連線模板。除非另行指定,否則元件類名將用作隱式bean定義名稱。

讓我們看看在這種情況下,我們的DBLoader宣告會是什麼樣子:

class DBLoader extends WiringDeclarableSupport implements CacheLoader {

  private DataSource dataSource;

  public void setDataSource(DataSource dataSource){
    this.dataSource = dataSource;
  }

  public Object load(LoaderHelper helper) { ... }
}
<cache-loader>
   <class-name>com.company.app.DBLoader</class-name>
   <!-- no parameter is passed (use the bean's implicit name, which is the class name) -->
</cache-loader>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
">

  <bean id="dataSource" ... />

  <!-- template bean definition -->
  <bean id="com.company.app.DBLoader" abstract="true" p:dataSource-ref="dataSource"/>
</beans>

在上述場景中,由於未指定引數,因此將ID/名稱為com.company.app.DBLoader的bean用作連線Pivotal GemFire建立的例項的模板。對於bean名稱使用不同約定的情況,可以在Pivotal GemFire配置中傳入bean-name引數:

<cache-loader>
   <class-name>com.company.app.DBLoader</class-name>
   <!-- pass the bean definition template name as parameter -->
   <parameter name="bean-name">
     <string>template-bean</string>
   </parameter>
</cache-loader>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
">

  <bean id="dataSource" ... />

   <!-- template bean definition -->
   <bean id="template-bean" abstract="true" p:dataSource-ref="dataSource"/>

</beans>
模板bean定義不必在XML中宣告。允許任何格式(Groovy、註解等)。

7.7.2. 使用自動裝配和註解進行配置

預設情況下,如果未找到bean定義,WiringDeclarableSupport自動裝配宣告例項。這意味著,除非例項提供任何依賴注入元資料,否則容器將查詢物件setter並嘗試自動滿足這些依賴項。但是,開發人員也可以使用JDK 5註解為自動裝配過程提供額外資訊。

我們強烈建議閱讀Spring文件中專門的章節,以獲取有關支援的註解和啟用因素的更多資訊。

例如,上述假設的DBLoader宣告可以透過以下方式注入Spring配置的DataSource

class DBLoader extends WiringDeclarableSupport implements CacheLoader {

  // use annotations to 'mark' the needed dependencies
  @javax.inject.Inject
  private DataSource dataSource;

  public Object load(LoaderHelper helper) { ... }
}
<cache-loader>
   <class-name>com.company.app.DBLoader</class-name>
   <!-- no need to declare any parameters since the class is auto-wired -->
</cache-loader>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
">

     <!-- enable annotation processing -->
     <context:annotation-config/>

</beans>

透過使用JSR-330註解,CacheLoader程式碼得到了簡化,因為DataSource的位置和建立已經外部化,使用者程式碼只關注載入過程。DataSource可以是事務性的、延遲建立的、在多個物件之間共享的或從JNDI檢索的。這些方面可以輕鬆地透過Spring容器配置和更改,而無需修改DBLoader程式碼。

7.8. Spring快取抽象支援

Spring Data for Pivotal GemFire提供了Spring 快取抽象的實現,將Pivotal GemFire定位為Spring快取基礎設施中的快取提供者

要將Pivotal GemFire用作後端實現,即Spring快取抽象中的“快取提供者”,只需將GemfireCacheManager新增到您的配置中:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xmlns:gfe="https://www.springframework.org/schema/gemfire"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/cache https://www.springframework.org/schema/cache/spring-cache.xsd
    https://www.springframework.org/schema/gemfire https://www.springframework.org/schema/gemfire/spring-gemfire.xsd
">

  <!-- enable declarative caching -->
  <cache:annotation-driven/>

  <gfe:cache id="gemfire-cache"/>

  <!-- declare GemfireCacheManager; must have a bean ID of 'cacheManager' -->
  <bean id="cacheManager" class="org.springframework.data.gemfire.cache.GemfireCacheManager"
      p:cache-ref="gemfire-cache">

</beans>
如果使用預設快取bean名稱(即“gemfireCache”),即沒有顯式ID的<gfe:cache>,則CacheManager bean定義上的cache-ref屬性不是必需的。

GemfireCacheManager(Singleton)bean例項被宣告並且宣告式快取被啟用時(無論是使用<cache:annotation-driven/>在XML中,還是使用Spring的@EnableCaching註解在JavaConfig中),Spring快取註解(例如@Cacheable)將識別使用Pivotal GemFire Region在記憶體中快取資料的“快取”。

這些快取(即Regions)必須在使用它們的快取註解之前存在,否則會發生錯誤。

舉例來說,假設您有一個客戶服務應用程式,其中包含一個執行快取的CustomerService應用程式元件……​

@Service
class CustomerService {

@Cacheable(cacheNames="Accounts", key="#customer.id")
Account createAccount(Customer customer) {
  ...
}

那麼您將需要以下配置。

XML

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xmlns:gfe="https://www.springframework.org/schema/gemfire"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/cache https://www.springframework.org/schema/cache/spring-cache.xsd
    https://www.springframework.org/schema/gemfire https://www.springframework.org/schema/gemfire/spring-gemfire.xsd
">

  <!-- enable declarative caching -->
  <cache:annotation-driven/>

  <bean id="cacheManager" class="org.springframework.data.gemfire.cache.GemfireCacheManager">

  <gfe:cache/>

  <gfe:partitioned-region id="accountsRegion" name="Accounts" persistent="true" ...>
    ...
  </gfe:partitioned-region>
</beans>

JavaConfig

@Configuration
@EnableCaching
class ApplicationConfiguration {

  @Bean
  CacheFactoryBean gemfireCache() {
    return new CacheFactoryBean();
  }

  @Bean
  GemfireCacheManager cacheManager() {
    GemfireCacheManager cacheManager = GemfireCacheManager();
    cacheManager.setCache(gemfireCache());
    return cacheManager;
  }

  @Bean("Accounts")
  PartitionedRegionFactoryBean accountsRegion() {
    PartitionedRegionFactoryBean accounts = new PartitionedRegionFactoryBean();

    accounts.setCache(gemfireCache());
    accounts.setClose(false);
    accounts.setPersistent(true);

    return accounts;
  }
}

當然,您可以自由選擇任何您喜歡的區域型別(例如,REPLICATE、PARTITION、LOCAL等)。

有關Spring快取抽象的更多詳情,請再次參考文件

8. 使用Pivotal GemFire序列化

為了提高Pivotal GemFire記憶體資料網格的整體效能,Pivotal GemFire支援一種名為PDX的專用序列化協議,它比標準Java序列化更快,結果更緊湊,並且可以透明地跨各種語言平臺(Java、C++和.NET)工作。

有關更多詳細資訊,請參見PDX序列化功能PDX序列化內部原理

本章討論了Spring Data for Pivotal GemFire簡化和改進Pivotal GemFire在Java中自定義序列化的各種方式。

8.1. 連線反序列化例項

序列化物件具有瞬態資料是相當常見的。瞬態資料通常取決於它在某個時間點所處的系統或環境。例如,DataSource是環境特定的。序列化此類資訊是無用的,甚至可能是危險的,因為它特定於某個VM或機器。對於這種情況,Spring Data for Pivotal GemFire提供了一個特殊的Instantiator,它為Pivotal GemFire在反序列化過程中建立的每個新例項執行連線。

透過這種機制,您可以依靠Spring容器來注入和管理某些依賴項,從而輕鬆地將瞬態資料與持久資料分開,並以透明的方式擁有豐富的領域物件。

Spring使用者可能會發現這種方法與@Configurable類似。WiringInstantiator的工作原理類似於WiringDeclarableSupport,它首先嚐試定位bean定義作為連線模板,否則回退到自動連線。

有關連線功能的更多詳細資訊,請參見上一節(連線Declarable元件)。

要使用SDG Instantiator,請將其宣告為bean,如下例所示:

<bean id="instantiator" class="org.springframework.data.gemfire.serialization.WiringInstantiator">
  <!-- DataSerializable type -->
  <constructor-arg>org.pkg.SomeDataSerializableClass</constructor-arg>
  <!-- type id -->
  <constructor-arg>95</constructor-arg>
</bean>

在Spring容器啟動期間,一旦初始化,Instantiator預設情況下會向Pivotal GemFire序列化系統註冊自己,並對Pivotal GemFire在反序列化期間建立的所有SomeDataSerializableClass例項執行連線。

8.2. 自動生成自定義Instantiators

對於資料密集型應用程式,隨著資料流入,每臺機器上可能會建立大量例項。Pivotal GemFire使用反射來建立新型別,但在某些情況下,這可能證明是昂貴的。一如既往,最好進行效能分析以量化是否存在這種情況。對於這種情況,Spring Data for Pivotal GemFire允許自動生成Instatiator類,這些類(使用預設建構函式)例項化新型別而無需使用反射。以下示例展示瞭如何建立例項化器:

<bean id="instantiatorFactory" class="org.springframework.data.gemfire.serialization.InstantiatorFactoryBean">
  <property name="customTypes">
    <map>
      <entry key="org.pkg.CustomTypeA" value="1025"/>
      <entry key="org.pkg.CustomTypeB" value="1026"/>
    </map>
  </property>
</bean>

前面的定義自動為兩個類(CustomTypeACustomTypeB)生成了兩個Instantiators,並使用使用者ID 10251026將它們註冊到Pivotal GemFire。這兩個Instantiators避免了使用反射,並直接透過Java程式碼建立例項。

9. POJO對映

本節內容

9.1. 物件對映基礎

本節涵蓋 Spring Data 物件對映、物件建立、欄位和屬性訪問、可變性與不可變性的基礎知識。請注意,本節僅適用於不使用底層資料儲存(如 JPA)物件對映的 Spring Data 模組。此外,請務必查閱儲存特定章節,瞭解儲存特定物件對映,例如索引、自定義列或欄位名稱等。

Spring Data 物件對映的核心職責是建立領域物件例項,並將儲存原生資料結構對映到這些例項上。這意味著我們需要兩個基本步驟

  1. 透過使用公開的建構函式之一建立例項。

  2. 例項填充以具體化所有公開的屬性。

9.1.1. 物件建立

Spring Data 會自動嘗試檢測持久化實體的建構函式,該建構函式將用於具體化該型別的物件。解析演算法的工作方式如下

  1. 如果有無引數建構函式,則使用它。其他建構函式將被忽略。

  2. 如果只有一個接受引數的建構函式,則使用它。

  3. 如果有多個接受引數的建構函式,則Spring Data將使用的建構函式必須使用@PersistenceConstructor進行註解。

值解析假定建構函式引數名與實體的屬性名匹配,即解析將按照屬性將要填充的方式執行,包括對映中的所有自定義(不同的資料儲存列或欄位名等)。這還要求類檔案中提供引數名資訊,或者建構函式上存在 @ConstructorProperties 註解。

值解析可以透過使用 Spring Framework 的 @Value 值註解和儲存特定的 SpEL 表示式進行自定義。請查閱有關儲存特定對映的部分以獲取更多詳細資訊。

物件建立內部

為了避免反射的開銷,Spring Data 物件建立預設使用執行時生成的工廠類,該類將直接呼叫域類的建構函式。即,對於此示例型別

class Person {
  Person(String firstname, String lastname) { … }
}

我們將在執行時建立一個在語義上等同於此的工廠類

class PersonObjectInstantiator implements ObjectInstantiator {

  Object newInstance(Object... args) {
    return new Person((String) args[0], (String) args[1]);
  }
}

這使我們獲得了大約 10% 的反射效能提升。為了使領域類符合此最佳化條件,它需要遵循一組約束

  • 它不能是私有類

  • 它不能是非靜態內部類

  • 它不能是 CGLib 代理類

  • Spring Data 將使用的建構函式不能是私有的

如果以上任何標準匹配,Spring Data 將回退到透過反射例項化實體。

9.1.2. 屬性填充

一旦建立了實體例項,Spring Data 會填充該類的所有剩餘持久化屬性。除非已由實體的建構函式填充(即透過其建構函式引數列表消耗),否則將首先填充識別符號屬性,以允許解析迴圈物件引用。之後,所有尚未由建構函式填充的非瞬態屬性將在實體例項上設定。為此,我們使用以下演算法

  1. 如果屬性是不可變的但公開了一個 wither 方法(見下文),我們使用 wither 方法建立一個帶有新屬性值的新實體例項。

  2. 如果定義了屬性訪問(即透過 getter 和 setter 訪問),我們將呼叫 setter 方法。

  3. 預設情況下,我們直接設定欄位值。

屬性填充內部

與我們的物件構造最佳化類似,我們也使用 Spring Data 執行時生成的訪問器類與實體例項進行互動。

class Person {

  private final Long id;
  private String firstname;
  private @AccessType(Type.PROPERTY) String lastname;

  Person() {
    this.id = null;
  }

  Person(Long id, String firstname, String lastname) {
    // Field assignments
  }

  Person withId(Long id) {
    return new Person(id, this.firstname, this.lastame);
  }

  void setLastname(String lastname) {
    this.lastname = lastname;
  }
}
示例 1. 生成的屬性訪問器
class PersonPropertyAccessor implements PersistentPropertyAccessor {

  private static final MethodHandle firstname;              (2)

  private Person person;                                    (1)

  public void setProperty(PersistentProperty property, Object value) {

    String name = property.getName();

    if ("firstname".equals(name)) {
      firstname.invoke(person, (String) value);             (2)
    } else if ("id".equals(name)) {
      this.person = person.withId((Long) value);            (3)
    } else if ("lastname".equals(name)) {
      this.person.setLastname((String) value);              (4)
    }
  }
}
1 PropertyAccessor 包含底層物件的可變例項。這是為了允許修改原本不可變的屬性。
2 預設情況下,Spring Data 使用欄位訪問來讀取和寫入屬性值。根據 private 欄位的可見性規則,使用 MethodHandles 與欄位互動。
3 該類公開了一個 withId(…) 方法,用於設定識別符號,例如當一個例項插入到資料儲存中並生成了識別符號時。呼叫 withId(…) 會建立一個新的 Person 物件。所有後續的修改都將在新例項中進行,而不會觸及舊例項。
4 使用屬性訪問允許直接方法呼叫而無需使用 MethodHandles

這使我們獲得了大約 25% 的反射效能提升。為了使領域類符合此最佳化條件,它需要遵循一組約束

  • 型別不能位於預設包或 java 包下。

  • 型別及其建構函式必須是 public

  • 作為內部類的型別必須是 static 的。

  • 所使用的 Java 執行時必須允許在原始 ClassLoader 中宣告類。Java 9 及更高版本施加了某些限制。

預設情況下,Spring Data 會嘗試使用生成的屬性訪問器,如果檢測到限制,則回退到基於反射的訪問器。

讓我們看看以下實體

示例 2. 示例實體
class Person {

  private final @Id Long id;                                                (1)
  private final String firstname, lastname;                                 (2)
  private final LocalDate birthday;
  private final int age; (3)

  private String comment;                                                   (4)
  private @AccessType(Type.PROPERTY) String remarks;                        (5)

  static Person of(String firstname, String lastname, LocalDate birthday) { (6)

    return new Person(null, firstname, lastname, birthday,
      Period.between(birthday, LocalDate.now()).getYears());
  }

  Person(Long id, String firstname, String lastname, LocalDate birthday, int age) { (6)

    this.id = id;
    this.firstname = firstname;
    this.lastname = lastname;
    this.birthday = birthday;
    this.age = age;
  }

  Person withId(Long id) {                                                  (1)
    return new Person(id, this.firstname, this.lastname, this.birthday, this.age);
  }

  void setRemarks(String remarks) {                                         (5)
    this.remarks = remarks;
  }
}
1 識別符號屬性是 final 的,但在建構函式中設定為 null。該類公開了一個 withId(…) 方法,用於設定識別符號,例如當例項插入資料儲存並生成識別符號時。原始的 Person 例項保持不變,因為建立了一個新的例項。同樣的模式通常也適用於其他由儲存管理但可能必須為持久化操作更改的屬性。
2 firstnamelastname 屬性是普通的不可變屬性,可能透過 getter 公開。
3 age 屬性是不可變的,但由 birthday 屬性派生。按照所示設計,資料庫值將優先於預設值,因為 Spring Data 使用唯一宣告的建構函式。即使目的是優先計算,重要的是此建構函式也接受 age 作為引數(可能忽略它),否則屬性填充步驟將嘗試設定 age 欄位,並因其不可變且不存在 wither 而失敗。
4 comment 屬性是可變的,並透過直接設定其欄位進行填充。
5 remarks 屬性是可變的,透過直接設定 comment 欄位或呼叫 setter 方法進行填充
6 該類公開了一個工廠方法和一個建構函式用於物件建立。這裡的核心思想是使用工廠方法而不是額外的建構函式,以避免透過@PersistenceConstructor進行建構函式歧義消除的需要。相反,屬性的預設值在工廠方法中處理。

9.1.3. 一般建議

  • 儘量堅持使用不可變物件 — 不可變物件建立起來很簡單,因為例項化一個物件就只剩下呼叫其構造函數了。此外,這避免了您的領域物件中充斥著允許客戶端程式碼操作物件狀態的 setter 方法。如果您需要這些方法,最好將它們設為包保護,以便只能由有限數量的協同定位型別呼叫。僅限建構函式的例項化比屬性填充快 30%。

  • 提供一個全參建構函式 — 即使您不能或不想將您的實體建模為不可變值,提供一個接受實體所有屬性(包括可變屬性)作為引數的建構函式仍然很有價值,因為這允許物件對映跳過屬性填充以獲得最佳效能。

  • 使用工廠方法而不是過載建構函式以避免@PersistenceConstructor —— 為了獲得最佳效能,需要一個全引數建構函式,我們通常希望公開更多特定於應用程式用例的建構函式,這些建構函式省略了諸如自動生成的識別符號等。使用靜態工廠方法來公開這些全引數建構函式的變體是一種成熟的模式。

  • 確保您遵守允許使用生成的例項化器和屬性訪問器類的約束 —— 

  • 為了生成識別符號,仍然使用帶有wither方法的final欄位 —— 

  • 使用 Lombok 避免樣板程式碼 — 由於持久化操作通常需要一個接受所有引數的建構函式,它們的宣告變成了繁瑣的樣板引數到欄位賦值的重複,最好透過使用 Lombok 的 @AllArgsConstructor 來避免。

9.1.4. Kotlin支援

Spring Data 適應 Kotlin 的特性,以允許物件建立和修改。

Kotlin 物件建立

Kotlin類支援例項化,所有類預設是不可變的,需要顯式屬性宣告來定義可變屬性。考慮以下dataPerson

data class Person(val id: String, val name: String)

上述類編譯成一個帶有顯式建構函式的典型類。我們可以透過新增另一個建構函式並用@PersistenceConstructor註解它來定製此類的建構函式偏好:

data class Person(var id: String, val name: String) {

    @PersistenceConstructor
    constructor(id: String) : this(id, "unknown")
}

Kotlin透過允許在未提供引數時使用預設值來支援引數可選性。當Spring Data檢測到具有引數預設值的建構函式時,如果資料儲存未提供值(或簡單地返回null),則會省略這些引數,以便Kotlin可以應用引數預設值。考慮以下對name應用引數預設值的類:

data class Person(var id: String, val name: String = "unknown")

每次 name 引數不在結果中或其值為 null 時,name 都會預設為 unknown

Kotlin 資料類的屬性填充

在 Kotlin 中,所有類預設都是不可變的,並且需要顯式屬性宣告來定義可變屬性。考慮以下 dataPerson

data class Person(val id: String, val name: String)

這個類實際上是不可變的。它允許建立新例項,因為 Kotlin 會生成一個 copy(…) 方法,該方法會建立新物件例項,複製現有物件的所有屬性值,並應用作為方法引數提供的屬性值。

9.2. 實體對映

Spring Data for Pivotal GemFire 提供對儲存在 Region 中的實體進行對映的支援。對映元資料透過在應用程式域類上使用註解來定義,如下例所示:

示例 3. 將域類對映到 Pivotal GemFire Region
@Region("People")
public class Person {

  @Id Long id;

  String firstname;
  String lastname;

  @PersistenceConstructor
  public Person(String firstname, String lastname) {
    // …
  }

  …
}

@Region註解可用於自定義Person類例項儲存的Region。@Id註解可用於註解應作為快取Region鍵的屬性,以標識Region條目。@PersistenceConstructor註解有助於消除多個可能可用的帶引數建構函式的歧義,並顯式將註解的建構函式標記為用於構建實體的建構函式。在沒有或只有一個建構函式的應用程式域類中,您可以省略此註解。

除了將實體儲存在頂級區域中,實體也可以儲存在子區域中,如下例所示:

@Region("/Users/Admin")
public class Admin extends User {
  …
}

@Region("/Users/Guest")
public class Guest extends User {
  …
}

請務必使用Pivotal GemFire Region的完整路徑,如透過使用<*-region>元素的idname屬性與Spring Data for Pivotal GemFire XML名稱空間定義的那樣。

9.2.1. 按區域型別劃分的實體對映

除了@Region註解之外,Spring Data for Pivotal GemFire還識別特定於型別的區域對映註解:@ClientRegion@LocalRegion@PartitionRegion@ReplicateRegion

在功能上,這些註解在SDG對映基礎設施中與通用@Region註解的處理方式完全相同。然而,這些額外的對映註解在Spring Data for Pivotal GemFire的註解配置模型中很有用。當與Spring @Configuration註解類上的@EnableEntityDefinedRegions配置註解結合使用時,可以在本地快取中生成區域,無論應用程式是客戶端還是對等體。

這些註解讓您能夠更具體地指定您的應用程式實體類應對映到哪種型別的Region,並且還對Region的資料管理策略產生影響(例如,分割槽(也稱為分片)與複製資料)。

在SDG註解配置模型中使用這些特定於型別的Region對映註解,可以省去您在配置中顯式定義這些Region的麻煩。

9.3. 儲存庫對映

作為在實體類上使用@Region註解指定實體儲存在哪個Region中的替代方法,您也可以在實體的Repository介面上指定@Region註解。有關更多詳細資訊,請參見Spring Data for Pivotal GemFire Repositories

但是,假設您想將Person記錄儲存在多個Pivotal GemFire Region中(例如,PeopleCustomers)。那麼您可以按如下方式定義相應的Repository介面擴充套件:

@Region("People")
public interface PersonRepository extends GemfireRepository<Person, String> {
…
}

@Region("Customers")
public interface CustomerRepository extends GemfireRepository<Person, String> {
...
}

然後,單獨使用每個Repository,您可以將實體儲存在多個Pivotal GemFire Region中,如下例所示:

@Service
class CustomerService {

  CustomerRepository customerRepo;

  PersonRepository personRepo;

  Customer update(Customer customer) {
    customerRepo.save(customer);
    personRepo.save(customer);
    return customer;
  }

您甚至可以將update服務方法包裝在Spring管理的事務中,無論是本地快取事務還是全域性事務。

9.4. MappingPdxSerializer

Spring Data for Pivotal GemFire 提供了一個自定義的PdxSerializer實現,名為MappingPdxSerializer,它使用Spring Data對映元資料來自定義實體序列化。

序列化器還允許您透過使用Spring Data EntityInstantiator抽象來定製實體例項化。預設情況下,序列化器使用ReflectionEntityInstantiator,它使用對映實體的持久化建構函式。持久化建構函式可以是預設建構函式、單獨宣告的建構函式,或顯式使用@PersistenceConstructor註解的建構函式。

為了為建構函式引數提供引數,序列化器從提供的PdxReader中讀取帶有命名建構函式引數的欄位,並透過使用Spring的@Value註解顯式標識,如下例所示:

示例 4. 在實體建構函式引數上使用@Value
public class Person {

  public Person(@Value("#root.thing") String firstName, @Value("bean") String lastName) {
    …
  }
}

以這種方式註解的實體類將從PdxReader中讀取“thing”欄位,並將其作為建構函式引數firstname的引數值傳遞。lastName的值是一個名為“bean”的Spring bean。

除了EntityInstantiators提供的自定義例項化邏輯和策略之外,MappingPdxSerializer還提供了超越Pivotal GemFire自身的ReflectionBasedAutoSerializer的能力。

雖然Pivotal GemFire的ReflectionBasedAutoSerializer方便地使用Java反射來填充實體,並使用正則表示式來識別應由序列化器處理(序列化和反序列化)的型別,但它無法像MappingPdxSerializer那樣執行以下操作:

  • 為每個實體欄位或屬性名稱和型別註冊自定義PdxSerializer物件。

  • 方便地識別ID屬性。

  • 自動處理只讀屬性。

  • 自動處理瞬態屬性。

  • 以空安全和型別安全的方式實現更強大的型別過濾(例如,不限於僅用正則表示式表達型別)。

現在我們更詳細地探討MappingPdxSerializer的每個特性。

9.4.1. 自定義PdxSerializer註冊

MappingPdxSerializer讓您能夠根據實體的欄位或屬性名稱和型別註冊自定義PdxSerializers

例如,假設您定義了一個建模User的實體型別,如下所示:

package example.app.security.auth.model;

public class User {

  private String name;

  private Password password;

  ...
}

雖然使用者的姓名可能不需要任何特殊的邏輯來序列化其值,但序列化密碼可能需要額外的邏輯來處理欄位或屬性的敏感性質。

也許您希望在客戶端和伺服器之間透過網路傳送密碼值時保護它,除了TLS之外,並且您只想儲存加鹽的雜湊。當使用MappingPdxSerializer時,您可以註冊一個自定義的PdxSerializer來處理使用者的密碼,如下所示:

示例 5. 按POJO欄位/屬性型別註冊自定義PdxSerializers
Map<?, PdxSerializer> customPdxSerializers = new HashMap<>();

customPdxSerializers.put(Password.class, new SaltedHashPasswordPdxSerializer());

mappingPdxSerializer.setCustomPdxSerializers(customPdxSerializers);

將應用程式定義的SaltedHashPasswordPdxSerializer例項註冊到Password應用程式域模型型別後,MappingPdxSerializer將查詢自定義PdxSerializer來序列化和反序列化所有Password物件,無論包含物件(例如User)如何。

但是,假設您只想自定義User物件上的Passwords序列化。為此,您可以透過指定Class欄位或屬性的完全限定名來為User型別註冊自定義PdxSerializer,如下例所示:

示例 6. 按POJO欄位/屬性名稱註冊自定義PdxSerializers
Map<?, PdxSerializer> customPdxSerializers = new HashMap<>();

customPdxSerializers.put("example.app.security.auth.model.User.password", new SaltedHashPasswordPdxSerializer());

mappingPdxSerializer.setCustomPdxSerializers(customPdxSerializers);

請注意使用完全限定的欄位或屬性名稱(即example.app.security.auth.model.User.password)作為自定義PdxSerializer註冊鍵。

您可以使用更具邏輯性的程式碼片段來構造註冊鍵,例如:User.class.getName().concat(".password");。我們建議使用此方法而不是前面顯示的示例。前面的示例試圖儘可能明確地說明註冊的語義。

9.4.2. 對映ID屬性

與Pivotal GemFire的ReflectionBasedAutoSerializer類似,SDG的MappingPdxSerializer也能夠確定實體的識別符號。但是,MappingPdxSerializer透過使用Spring Data的對映元資料來做到這一點,特別是透過使用Spring Data的@Id註解找到被指定為識別符號的實體屬性。或者,任何名為“id”且未明確使用@Id註解的欄位或屬性也被指定為實體的識別符號。

例如:

class Customer {

  @Id
  Long id;

  ...
}

在這種情況下,在序列化期間呼叫PdxSerializer.toData(..)方法時,Customerid欄位透過使用PdxWriter.markIdentifierField(:String)被標記為PDX型別元資料中的識別符號欄位。

9.4.3. 對映只讀屬性

當您的實體定義只讀屬性時會發生什麼?

首先,瞭解什麼是“只讀”屬性很重要。如果您按照JavaBeans規範(如Spring所做)定義POJO,您可能會定義一個具有隻讀屬性的POJO,如下所示:

package example;

class ApplicationDomainType {

  private AnotherType readOnly;

  public AnotherType getReadOnly() [
    this.readOnly;
  }

  ...
}

readOnly屬性是隻讀的,因為它不提供setter方法。它只有一個getter方法。在這種情況下,readOnly屬性(不要與readOnly DomainType欄位混淆)被認為是隻讀的。

因此,在反序列化期間,當在PdxSerializer.fromData(:Class<ApplicationDomainType>, :PdxReader)方法中填充ApplicationDomainType例項時,MappingPdxSerializer不會嘗試為該屬性設定值,特別是如果PDX序列化位元組中存在值。

這在您可能返回某個實體型別的檢視或投影,並且只想設定可寫狀態的情況下非常有用。也許實體的檢視或投影基於授權或其他標準。關鍵是,您可以根據應用程式的用例和要求適當地利用此功能。如果您希望欄位或屬性始終被寫入,只需定義一個setter方法。

9.4.4. 對映瞬態屬性

同樣,當您的實體定義transient屬性時會發生什麼?

您會期望您的實體的transient欄位或屬性在序列化實體時不會序列化到PDX。這正是發生的情況,與Pivotal GemFire自己的ReflectionBasedAutoSerializer不同,後者透過Java反射序列化物件中可訪問的一切。

MappingPdxSerializer不會序列化任何被限定為瞬態的欄位或屬性,無論是透過使用Java自己的transient關鍵字(在類例項欄位的情況下),還是透過在欄位或屬性上使用@Transient Spring Data註解。

例如,您可以透過以下方式定義具有瞬態欄位和屬性的實體:

package example;

class Process {

  private transient int id;

  private File workingDirectory;

  private String name;

  private Type type;

  @Transient
  public String getHostname() {
    ...
  }

  ...
}

Processid欄位和可讀的hostname屬性都不會寫入PDX。

9.4.5. 按類型別過濾

與Pivotal GemFire的ReflectionBasedAutoSerializer類似,SDG的MappingPdxSerializer允許您過濾要序列化和反序列化的物件型別。

然而,與Pivotal GemFire的ReflectionBasedAutoSerializer使用複雜的正則表示式來表達序列化器處理的型別不同,SDG的MappingPdxSerializer使用更強大的java.util.function.Predicate介面和API來表達型別匹配標準。

如果您喜歡使用正則表示式,可以使用Java的正則表示式支援實現Predicate

Java的Predicate介面的優點是,您可以使用方便且適當的API方法組合Predicates,包括:and(:Predicate)or(:Predicate)negate()

以下示例展示了Predicate API的實際應用:

Predicate<Class<?>> customerTypes =
  type -> Customer.class.getPackage().getName().startsWith(type.getName()); // Include all types in the same package as `Customer`

Predicate includedTypes = customerTypes
  .or(type -> User.class.isAssignble(type)); // Additionally, include User sub-types (e.g. Admin, Guest, etc)

mappingPdxSerializer.setIncludeTypeFilters(includedTypes);

mappingPdxSerializer.setExcludeTypeFilters(
  type -> !Reference.class.getPackage(type.getPackage()); // Exclude Reference types
傳遞給您的Predicate的任何Class物件都保證不為null

SDG的MappingPdxSerializer包含對包括和排除類型別過濾器的支援。

排除型別過濾

預設情況下,SDG的MappingPdxSerializer註冊預定義的Predicates,它們過濾或排除以下包中的型別:

  • java.*

  • com.gemstone.gemfire.*

  • org.apache.geode.*

  • org.springframework.*

此外,MappingPdxSerializer在呼叫PdxSerializer.toData(:Object, :PdxWriter)時過濾null物件,在呼叫PdxSerializer.fromData(:Class<?>, :PdxReader)方法時過濾null類型別。

透過簡單地定義Predicate並將其新增到MappingPdxSerializer,如前所示,可以非常容易地為其他類型別或整個包的型別新增排除項。

MappingPdxSerializer.setExcludeTypeFilters(:Predicate<Class<?>>)方法是累加的,這意味著它使用Predicate.and(:Predicate<Class<?>>)方法將您的應用程式定義的型別過濾器與上面指出的現有預定義型別過濾器Predicates進行組合。

但是,如果您想包含被排除型別過濾器隱式排除的類型別(例如java.security Principal),該怎麼辦?請參閱包含型別過濾

包含型別過濾

如果您想顯式包含一個類型別,或覆蓋一個隱式排除應用程式所需類型別(例如java.security.Principal,它預設被MappingPdxSerializer上的java.*包排除型別過濾器排除)的類型別過濾器,那麼只需定義適當的Predicate並使用MappingPdxSerializer.setIncludeTypeFilters(:Predicate<Class<?>>)方法將其新增到序列化器中,如下所示:

Predicate<Class<?>> principalTypeFilter =
  type -> java.security.Principal.class.isAssignableFrom(type);

mappingPdxSerializer.setIncludeTypeFilters(principalTypeFilters);

同樣,MappingPdxSerializer.setIncludeTypeFilters(:Predicate<Class<?>>)方法,像setExcludeTypeFilters(:Predicate<Class<?>>)一樣,是累加的,因此使用Predicate.or(:Predicate<Class<?>>)組合任何傳入的型別過濾器。這意味著您可以根據需要多次呼叫setIncludeTypeFilters(:Predicate<Class<?>>)

當存在包含型別過濾器時,MappingPdxSerializer會根據類型別是否未被隱式排除或是否被顯式包含(兩者中任何一個返回true)來決定是否反/序列化類型別的例項。然後,該類型別的例項將被適當地序列化或反序列化。

例如,當如前所示顯式註冊Predicate<Class<Principal>>的型別過濾器時,它會取消對java.*包型別的隱式排除型別過濾器。

10. Spring Data for Pivotal GemFire Repositories

Spring Data for Pivotal GemFire 提供對使用 Spring Data Repository 抽象的支援,以便輕鬆將實體持久化到 Pivotal GemFire 中並執行查詢。Repository 程式設計模型的概述請參見此處

10.1. Spring XML配置

要引導Spring Data Repositories,請使用Spring Data for Pivotal GemFire Data名稱空間中的<repositories/>元素,如下例所示:

示例 7. 在XML中引導Spring Data for Pivotal GemFire Repositories
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:gfe-data="https://www.springframework.org/schema/data/gemfire"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    https://www.springframework.org/schema/data/gemfire https://www.springframework.org/schema/data/gemfire/spring-data-gemfire.xsd
">

  <gfe-data:repositories base-package="com.example.acme.repository"/>

</beans>

上述配置片段查詢配置的基本包下的介面,併為這些介面建立由SimpleGemfireRepository支援的Repository例項。

除非您的應用程式域類正確對映到配置的區域,否則引導過程將失敗。

10.2. Spring基於Java的配置

或者,許多開發人員更喜歡使用Spring的基於Java的容器配置

使用此方法,您可以使用SDG @EnableGemfireRepositories註解引導Spring Data Repositories,如下例所示:

示例 8. 使用@EnableGemfireRepositories引導Spring Data for Pivotal GemFire Repositories
@SpringBootApplication
@EnableGemfireRepositories(basePackages = "com.example.acme.repository")
class SpringDataApplication {
  ...
}

您可以不使用basePackages屬性,而是選擇使用型別安全的basePackageClasses屬性。basePackageClasses允許您透過僅指定一個應用程式Repository介面型別來指定包含所有應用程式Repository類的包。考慮在每個包中建立一個特殊的無操作標記類或介面,其目的只是為了標識此屬性引用的應用程式Repository的位置。

除了basePackagesbasePackageClasses屬性之外,與Spring的@ComponentScan註解一樣,@EnableGemfireRepositories註解提供了基於Spring的ComponentScan.Filter型別的包含和排除過濾器。您可以使用filterType屬性按不同方面進行過濾,例如應用程式Repository型別是否使用特定註解進行註解,或是否擴充套件特定類型別等。有關更多詳細資訊,請參閱FilterType Javadoc

@EnableGemfireRepositories註解還允許您透過使用namedQueriesLocation屬性指定位於Java Properties檔案中的命名OQL查詢的位置。屬性名稱必須與Repository查詢方法的名稱匹配,屬性值是當Repository查詢方法被呼叫時您希望執行的OQL查詢。

如果您的應用程式需要一個或多個自定義儲存庫實現,則可以將repositoryImplementationPostfix屬性設定為備用值(預設為Impl)。此功能通常用於擴充套件Spring Data Repository基礎設施,以實現資料儲存(例如SDG)未提供的功能。

Pivotal GemFire中需要自定義儲存庫實現的一個示例是在執行連線時。SDG儲存庫不支援連線。對於Pivotal GemFire的PARTITION區域,連線必須在共置的PARTITION區域上執行,因為Pivotal GemFire不支援“分散式”連線。此外,等值連線OQL查詢必須在Pivotal GemFire函式內部執行。有關Pivotal GemFire等值連線查詢的更多詳細資訊,請參見此處

SDG的儲存庫基礎設施擴充套件的許多其他方面也可以定製。有關所有配置設定的更多詳細資訊,請參見@EnableGemfireRepositories Javadoc。

10.3. 執行OQL查詢

Spring Data for Pivotal GemFire Repositories允許定義查詢方法,以便輕鬆地針對託管實體對映到的區域執行Pivotal GemFire OQL查詢,如下例所示:

示例 9. 示例儲存庫
@Region("People")
public class Person { … }
public interface PersonRepository extends CrudRepository<Person, Long> {

  Person findByEmailAddress(String emailAddress);

  Collection<Person> findByFirstname(String firstname);

  @Query("SELECT * FROM /People p WHERE p.firstname = $1")
  Collection<Person> findByFirstnameAnnotated(String firstname);

  @Query("SELECT * FROM /People p WHERE p.firstname IN SET $1")
  Collection<Person> findByFirstnamesAnnotated(Collection<String> firstnames);
}

上述示例中列出的第一個查詢方法將導致派生以下OQL查詢:SELECT x FROM /People x WHERE x.emailAddress = $1。第二個查詢方法以相同的方式工作,只是它返回所有找到的實體,而第一個查詢方法期望找到單個結果。

如果支援的關鍵字不足以宣告和表達您的OQL查詢,或者方法名變得過於冗長,那麼您可以像第三和第四個方法所示,用@Query註解查詢方法。

下表簡要列出了查詢方法中支援的關鍵字示例:

表 4. 查詢方法支援的關鍵字
關鍵字 示例 邏輯結果

GreaterThan

findByAgeGreaterThan(int age)

x.age > $1

GreaterThanEqual

findByAgeGreaterThanEqual(int age)

x.age >= $1

LessThan

findByAgeLessThan(int age)

x.age < $1

LessThanEqual

findByAgeLessThanEqual(int age)

x.age <= $1

IsNotNull, NotNull

findByFirstnameNotNull()

x.firstname =! NULL

IsNull, Null

findByFirstnameNull()

x.firstname = NULL

In

findByFirstnameIn(Collection x)

x.firstname IN SET $1

NotIn

findByFirstnameNotIn(Collection x)

x.firstname NOT IN SET $1

IgnoreCase

findByFirstnameIgnoreCase(String firstName)

x.firstname.equalsIgnoreCase($1)

(無關鍵字)

findByFirstname(String name)

x.firstname = $1

Like

findByFirstnameLike(String name)

x.firstname LIKE $1

Not

findByFirstnameNot(String name)

x.firstname != $1

IsTrue, True

findByActiveIsTrue()

x.active = true

IsFalse, False

findByActiveIsFalse()

x.active = false

10.4. 使用註解的OQL查詢擴充套件

許多查詢語言,例如Pivotal GemFire的OQL(物件查詢語言),具有Spring Data Commons儲存庫基礎設施不直接支援的擴充套件。

Spring Data Commons儲存庫基礎設施的目標之一是充當最低公分母,以保持對當今應用程式開發中可用和使用的最廣泛資料儲存的支援和可移植性。從技術上講,這意味著開發人員可以透過重用現有的特定於應用程式的儲存庫介面來訪問應用程式中Spring Data Commons支援的多個不同資料儲存——這是一種方便而強大的抽象。

為了支援Pivotal GemFire的OQL查詢語言擴充套件並保持跨不同資料儲存的可移植性,Spring Data for Pivotal GemFire透過使用Java註解添加了對OQL查詢擴充套件的支援。這些註解將被其他Spring Data Repository實現(例如Spring Data JPA或Spring Data Redis)忽略,因為它們沒有類似的查詢語言特性。

例如,許多資料儲存很可能不實現Pivotal GemFire的OQL IMPORT關鍵字。將IMPORT作為註解(即@Import)而不是作為查詢方法簽名的一部分(特別是方法“名稱”)實現,在評估查詢方法名稱以構建另一個適合資料儲存語言的查詢時,不會干擾解析基礎設施。

目前,Spring Data for Pivotal GemFire支援的Pivotal GemFire OQL查詢語言擴充套件集包括:

表 5. Repository查詢方法支援的Pivotal GemFire OQL擴充套件
關鍵字 註解 描述 引數

HINT

@Hint

OQL查詢索引提示

String[](例如@Hint({ "IdIdx", "TxDateIdx" }))

IMPORT

@Import

限定應用程式特定型別。

String(例如@Import("org.example.app.domain.Type"))

LIMIT

@Limit

限制返回的查詢結果集。

Integer(例如@Limit(10);預設值為Integer.MAX_VALUE)

TRACE

@Trace

啟用OQL查詢特定的除錯。

不適用

例如,假設您有一個Customers應用程式域類和相應的Pivotal GemFire Region,以及一個CustomerRepository和一個按姓氏查詢Customers的查詢方法,如下所示:

示例 10. 示例客戶儲存庫
package ...;

import org.springframework.data.annotation.Id;
import org.springframework.data.gemfire.mapping.annotation.Region;
...

@Region("Customers")
public class Customer ... {

  @Id
  private Long id;

  ...
}
package ...;

import org.springframework.data.gemfire.repository.GemfireRepository;
...

public interface CustomerRepository extends GemfireRepository<Customer, Long> {

  @Trace
  @Limit(10)
  @Hint("LastNameIdx")
  @Import("org.example.app.domain.Customer")
  List<Customer> findByLastName(String lastName);

  ...
}

上述示例將生成以下OQL查詢:

<TRACE> <HINT 'LastNameIdx'> IMPORT org.example.app.domain.Customer; SELECT * FROM /Customers x WHERE x.lastName = $1 LIMIT 10

Spring Data for Pivotal GemFire的Repository擴充套件在OQL註解擴充套件與@Query註解結合使用時,會小心避免建立衝突的宣告。

另一個例子是,假設您在CustomerRepository中定義了一個原始的@Query註解查詢方法,如下所示:

示例 11. CustomerRepository
public interface CustomerRepository extends GemfireRepository<Customer, Long> {

  @Trace
  @Limit(10)
  @Hint("CustomerIdx")
  @Import("org.example.app.domain.Customer")
  @Query("<TRACE> <HINT 'ReputationIdx'> SELECT DISTINCT * FROM /Customers c WHERE c.reputation > $1 ORDER BY c.reputation DESC LIMIT 5")
  List<Customer> findDistinctCustomersByReputationGreaterThanOrderByReputationDesc(Integer reputation);

}

上述查詢方法將生成以下OQL查詢:

IMPORT org.example.app.domain.Customer; <TRACE> <HINT 'ReputationIdx'> SELECT DISTINCT * FROM /Customers x WHERE x.reputation > $1 ORDER BY c.reputation DESC LIMIT 5

@Limit(10)註解不會覆蓋原始查詢中顯式定義的LIMIT。同樣,@Hint("CustomerIdx")註解也不會覆蓋原始查詢中顯式定義的HINT。最後,@Trace註解是冗餘的,沒有額外的效果。

ReputationIdx索引可能不是最明智的索引,因為許多客戶可能具有相同的聲譽值,這降低了索引的有效性。請明智地選擇索引和其他最佳化,因為不當或選擇不佳的索引可能會由於維護索引的開銷而對效能產生相反的影響。ReputationIdx僅用於示例目的。

10.5. 查詢後處理

由於使用了Spring Data Repository抽象,定義資料儲存特定查詢(例如OQL)的查詢方法約定既簡單又方便。然而,有時仍然希望檢查甚至可能修改從Repository查詢方法生成的查詢。

自2.0.x起,Spring Data for Pivotal GemFire 包含了o.s.d.gemfire.repository.query.QueryPostProcessor函式式介面。該介面的定義大致如下:

示例 12. QueryPostProcessor
package org.springframework.data.gemfire.repository.query;

import org.springframework.core.Ordered;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.QueryMethod;
import ...;

@FunctionalInterface
interface QueryPostProcessor<T extends Repository, QUERY> extends Ordered {

  QUERY postProcess(QueryMethod queryMethod, QUERY query, Object... arguments);

}

還提供了額外的預設方法,允許您組合QueryPostProcessor例項,類似於java.util.function.Function.andThen(:Function)java.util.function.Function.compose(:Function)的工作方式。

此外,QueryPostProcessor介面實現了org.springframework.core.Ordered介面,當在Spring容器中宣告和註冊多個QueryPostProcessors並用於為一組生成的查詢方法查詢建立處理管道時,這很有用。

最後,QueryPostProcessor接受與型別引數TQUERY相對應的型別引數。型別T擴充套件了Spring Data Commons標記介面org.springframework.data.repository.Repository。我們將在本節後面進一步討論。Spring Data for Pivotal GemFire中所有QUERY型別引數的引數都是java.lang.String型別。

將查詢定義為QUERY型別是有用的,因為此QueryPostProcessor介面可能會移植到Spring Data Commons,因此必須處理不同資料儲存(如JPA、MongoDB或Redis)的所有形式的查詢。

您可以實現此介面,以便在呼叫應用程式Repository介面方法時,接收包含從該方法生成的查詢的回撥。

例如,您可能希望記錄所有應用程式儲存庫介面定義中的所有查詢。您可以透過使用以下QueryPostProcessor實現來實現這一點:

示例 13. LoggingQueryPostProcessor
package example;

import ...;

class LoggingQueryPostProcessor implements QueryPostProcessor<Repository, String> {

  private Logger logger = Logger.getLogger("someLoggerName");

  @Override
  public String postProcess(QueryMethod queryMethod, String query, Object... arguments) {

      String message = String.format("Executing query [%s] with arguments [%s]", query, Arrays.toString(arguments));

      this.logger.info(message);
  }
}

LoggingQueryPostProcessor被型別化為Spring Data org.springframework.data.repository.Repository標記介面,因此會記錄所有應用程式儲存庫介面查詢方法生成的查詢。

您可以將此日誌記錄的範圍限制為僅來自某些型別的應用程式儲存庫介面的查詢,例如,一個CustomerRepository,如下例所示:

示例 14. CustomerRepository
interface CustomerRepository extends CrudRepository<Customer, Long> {

  Customer findByAccountNumber(String accountNumber);

  List<Customer> findByLastNameLike(String lastName);

}

然後,您可以將LoggingQueryPostProcessor專門型別化為CustomerRepository,如下所示:

示例 15. CustomerLoggingQueryPostProcessor
class LoggingQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> { .. }

因此,只有在CustomerRepository介面中定義的查詢(例如findByAccountNumber)才會被記錄。

您可能希望為由儲存庫查詢方法定義的特定查詢建立QueryPostProcessor。例如,假設您希望將從CustomerRepository.findByLastNameLike(:String)查詢方法生成的OQL查詢限制為僅返回五個結果,並按firstName升序排序Customers。為此,您可以定義一個自定義QueryPostProcessor,如下例所示:

示例 16. OrderedLimitedCustomerByLastNameQueryPostProcessor
class OrderedLimitedCustomerByLastNameQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> {

  private final int limit;

  public OrderedLimitedCustomerByLastNameQueryPostProcessor(int limit) {
    this.limit = limit;
  }

  @Override
  public String postProcess(QueryMethod queryMethod, String query, Object... arguments) {

    return "findByLastNameLike".equals(queryMethod.getName())
      ? query.trim()
          .replace("SELECT", "SELECT DISTINCT")
          .concat(" ORDER BY firstName ASC")
          .concat(String.format(" LIMIT %d", this.limit))
      : query;
  }
}

雖然上述示例有效,但您可以使用Spring Data for Pivotal GemFire提供的Spring Data Repository約定來實現相同的效果。例如,相同的查詢可以定義如下:

示例 17. 使用約定的CustomerRepository
interface CustomerRepository extends CrudRepository<Customer, Long> {

  @Limit(5)
  List<Customer> findDistinctByLastNameLikeOrderByFirstNameDesc(String lastName);

}

但是,如果您無法控制應用程式CustomerRepository介面定義,那麼QueryPostProcessor(即OrderedLimitedCustomerByLastNameQueryPostProcessor)就很方便。

如果您希望確保LoggingQueryPostProcessor始終在Spring ApplicationContext中可能已宣告和註冊的其他應用程式定義的QueryPostProcessors之後執行,您可以透過覆蓋o.s.core.Ordered.getOrder()方法來設定order屬性,如下例所示:

示例 18. 定義order屬性
class LoggingQueryPostProcessor implements QueryPostProcessor<Repository, String> {

  @Override
  int getOrder() {
    return 1;
  }
}

class CustomerQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> {

  @Override
  int getOrder() {
    return 0;
  }
}

這確保您始終在LoggingQueryPostProcessor記錄查詢之前看到其他QueryPostProcessors應用後處理的效果。

您可以在Spring ApplicationContext中定義任意數量的QueryPostProcessors,並以任何順序將它們應用於所有或特定的應用程式Repository介面,並透過使用提供給postProcess(..)方法回撥的引數來達到您想要的粒度。

11. 函式執行的註解支援

Spring Data for Pivotal GemFire 包含註解支援,以簡化使用 Pivotal GemFire 函式執行

在底層,Pivotal GemFire API提供了類來實現在Pivotal GemFire伺服器上部署的Pivotal GemFire函式並進行註冊,然後這些函式可以由其他對等成員應用程式或從快取客戶端遠端呼叫。

函式可以並行執行,分佈在叢集中的多個Pivotal GemFire伺服器上,使用map-reduce模式聚合結果並返回給呼叫者。函式也可以被指定在單個伺服器或Region上執行。Pivotal GemFire API支援透過各種預定義範圍(在Region上、在成員上(分組)、在伺服器上等)遠端執行函式。遠端函式的實現和執行,與任何RPC協議一樣,需要一些樣板程式碼。

Spring Data for Pivotal GemFire秉承Spring的核心價值主張,旨在隱藏遠端函式執行的機制,讓您專注於核心POJO程式設計和業務邏輯。為此,Spring Data for Pivotal GemFire引入了註解,以宣告式地將POJO類的公共方法註冊為Pivotal GemFire函式,以及透過使用註解介面來呼叫已註冊函式(包括遠端呼叫)的功能。

11.1. 實現與執行

需要解決兩個獨立的關注點:實現和執行。

第一個是函式實現(伺服器端),它必須與FunctionContext互動以訪問呼叫引數、ResultsSender以傳送結果以及其他執行上下文資訊。函式實現通常訪問快取和區域,並使用唯一ID向FunctionService註冊。

呼叫函式的快取客戶端應用程式不依賴於實現。為了呼叫函式,應用程式例項化一個Execution,提供函式ID、呼叫引數和函式目標,該目標定義其範圍:區域、伺服器、伺服器組、成員或成員組。如果函式產生結果,呼叫者使用ResultCollector聚合和獲取執行結果。在某些情況下,需要自定義ResultCollector實現,並且可以向Execution註冊。

這裡的“客戶端”和“伺服器”是在函式執行的上下文中使用的,這可能與Pivotal GemFire客戶端-伺服器拓撲中的客戶端和伺服器具有不同的含義。雖然使用ClientCache例項的應用程式通常在叢集中的一個或多個Pivotal GemFire伺服器上呼叫函式,但也可以在對等(P2P)配置中執行函式,其中應用程式是託管對等Cache例項的叢集成員。請記住,對等成員快取應用程式受作為叢集對等成員的所有約束。

11.2. 實現函式

使用Pivotal GemFire API,FunctionContext提供了一個執行時呼叫上下文,其中包括客戶端的呼叫引數和ResultSender實現,用於將結果傳送回客戶端。此外,如果函式在Region上執行,FunctionContext實際上是RegionFunctionContext的一個例項,它提供了額外的資訊,例如函式被呼叫的目標Region、與Execution關聯的任何過濾器(一組特定鍵)等。如果Region是PARTITION Region,函式應該使用PartitionRegionHelper來提取本地資料集。

透過使用Spring,您可以編寫一個簡單的POJO,並使用Spring容器將您的一個或多個POJO的公共方法繫結到一個函式。旨在用作函式的POJO方法的簽名通常必須符合客戶端的執行引數。但是,在區域執行的情況下,也可以提供區域資料(據推測,如果區域是PARTITION區域,則資料儲存在本地分割槽中)。

此外,函式可能需要應用的過濾器(如果有)。這表明客戶端和伺服器共享呼叫引數的契約,但方法簽名可能包含額外的引數,用於傳遞由FunctionContext提供的值。一種可能性是客戶端和伺服器共享一個公共介面,但這並非嚴格要求。唯一的約束是方法簽名包含與函式呼叫時相同的呼叫引數序列,這些引數在額外引數解析後必須完全對應。

例如,假設客戶端提供一個String和一個int作為呼叫引數。這些引數作為陣列在FunctionContext中提供,如下例所示:

Object[] args = new Object[] { "test", 123 };

Spring容器應該能夠繫結到類似於以下任何方法簽名(暫時忽略返回型別):

public Object method1(String s1, int i2) { ... }
public Object method2(Map<?, ?> data, String s1, int i2) { ... }
public Object method3(String s1, Map<?, ?> data, int i2) { ... }
public Object method4(String s1, Map<?, ?> data, Set<?> filter, int i2) { ... }
public void method4(String s1, Set<?> filter, int i2, Region<?,?> data) { ... }
public void method5(String s1, ResultSender rs, int i2) { ... }
public void method6(FunctionContest context) { ... }

一般規則是,一旦解析了任何額外引數(即區域資料和過濾器),剩餘的引數必須與預期的函式方法引數在順序和型別上完全一致。方法的返回型別必須為void或可序列化的型別(作為java.io.SerializableDataSerializablePdxSerializable)。後者也是呼叫引數的要求。

區域資料通常應定義為Map,以方便單元測試,但如有必要,也可以是Region型別。如上例所示,如果您需要控制結果如何返回給客戶端,也可以直接傳遞FunctionContext本身或ResultSender

11.2.1. 用於函式實現的註解

以下示例展示了SDG的函式註解如何用於將POJO方法公開為Pivotal GemFire函式:

@Component
public class ApplicationFunctions {

   @GemfireFunction
   public String function1(String value, @RegionData Map<?, ?> data, int i2) { ... }

   @GemfireFunction(id = "myFunction", batchSize=100, HA=true, optimizedForWrite=true)
   public List<String> function2(String value, @RegionData Map<?, ?> data, int i2, @Filter Set<?> keys) { ... }

   @GemfireFunction(hasResult=true)
   public void functionWithContext(FunctionContext functionContext) { ... }

}

請注意,該類本身必須註冊為Spring bean,並且每個Pivotal GemFire函式都用@GemfireFunction註解。在前面的示例中,使用了Spring的@Component註解,但您可以使用Spring支援的任何方法(例如XML配置或在使用Spring Boot時使用Java配置類)註冊bean。這使得Spring容器能夠建立該類的例項並將其包裝在PojoFunctionWrapper中。Spring為每個用@GemfireFunction註解的方法建立一個包裝器例項。每個包裝器例項共享相同的目標物件例項來呼叫相應的方法。

POJO Function類是Spring bean這一事實可能帶來其他好處。由於它與Pivotal GemFire元件(如快取和區域)共享ApplicationContext,因此如有必要,可以將這些元件注入到類中。

Spring 建立包裝器類並將函式註冊到 Pivotal GemFire 的 FunctionService。用於註冊每個函式的函式 ID 必須是唯一的。按照約定,它預設為簡單(非限定)方法名。可以使用 @GemfireFunction 註解的 id 屬性顯式定義名稱。

@GemfireFunction註解還提供了其他配置屬性:HAoptimizedForWrite,它們對應於Pivotal GemFire的Function介面定義的屬性。

如果POJO函式方法的返回型別是void,則hasResult屬性會自動設定為false。否則,如果方法返回一個值,則hasResult屬性設定為true。即使對於void方法返回型別,GemfireFunction註解的hasResult屬性也可以設定為true以覆蓋此約定,如前面所示的functionWithContext方法。據推測,其意圖是您將直接使用ResultSender將結果傳送給呼叫者。

最後,GemfireFunction 註解支援 requiredPermissions 屬性,該屬性指定執行 Function 所需的許可權。預設情況下,所有 Function 都需要 DATA:WRITE 許可權。該屬性接受一個字串陣列,允許您根據應用程式和/或 Function UC 的需要修改許可權。每個資源許可權的預期格式如下:<RESOURCE>:<OPERATION>:[Target]:[Key]

RESOURCE 可以是 {data-store-javadoc]/org/apache/geode/security/ResourcePermission.Resource.html[ResourcePermission.Resource] 列舉值之一。OPERATION 可以是 {data-store-javadoc}/org/apache/geode/security/ResourcePermission.Operation.html[ResourcePermission.Operation] 列舉值之一。可選地,Target 可以是 Region 的名稱或 {data-store-javadoc}/org/apache/geode/security/ResourcePermission.Target.html[ResourcePermission.Target] 列舉值之一。最後,可選地,如果指定了 Target Region,則 Key 是該 Region 中的有效 Key。

PojoFunctionWrapper 實現了 Pivotal GemFire 的 Function 介面,繫結方法引數,並在其 execute() 方法中呼叫目標方法。它還使用 ResultSender 將方法的返回值傳送回撥用者。

11.2.2. 批次處理結果

如果返回型別是陣列或 Collection,則必須考慮如何返回結果。預設情況下,PojoFunctionWrapper 一次返回整個陣列或 Collection。如果陣列或 Collection 中的元素數量非常大,可能會帶來效能損失。要將有效負載分成更小、更易於管理的塊,您可以設定 batchSize 屬性,如前面所示的 function2 中所示。

如果您需要對 ResultSender 進行更多控制,特別是當方法本身會使用過多記憶體來建立 Collection 時,您可以傳入 ResultSender 或透過 FunctionContext 訪問它,並在方法中直接使用它將結果傳送回撥用者。

11.2.3. 啟用註解處理

根據 Spring 標準,您必須明確啟用 @GemfireFunction 註解的註解處理。以下示例使用 XML 啟用註解處理

<gfe:annotation-driven/>

以下示例透過註解 Java 配置類來啟用註解處理

@Configuration
@EnableGemfireFunctions
class ApplicationConfiguration { ... }

11.3. 執行函式

呼叫遠端 Function 的程序需要提供 Function 的 ID、呼叫引數、執行目標(onRegiononServersonServeronMemberonMembers)以及(可選)過濾集。透過使用 Spring Data for Pivotal GemFire,您只需定義一個由註解支援的介面。Spring 為該介面建立一個動態代理,該代理使用 FunctionService 來建立 Execution、呼叫 Execution,並在必要時將結果強制轉換為定義的返回型別。此技術類似於 Spring Data for Pivotal GemFire 的 Repository 擴充套件的工作方式。因此,一些配置和概念應該很熟悉。

通常,單個介面定義對映到多個 Function 執行,每個執行對應於介面中定義的每個方法。

11.3.1. 用於函式執行的註解

為了支援客戶端 Function 執行,提供了以下 SDG Function 註解:@OnRegion@OnServer@OnServers@OnMember@OnMembers。這些註解對應於 Pivotal GemFire 的 FunctionService 類提供的 Execution 實現。

每個註解都公開了適當的屬性。這些註解還提供了一個可選的 resultCollector 屬性,其值是實現 ResultCollector 介面的 Spring bean 的名稱,用於執行。

代理介面將所有宣告的方法繫結到相同的執行配置。雖然預計單方法介面很常見,但介面中的所有方法都由相同的代理例項支援,因此都共享相同的配置。

以下清單顯示了一些示例

@OnRegion(region="SomeRegion", resultCollector="myCollector")
public interface FunctionExecution {

    @FunctionId("function1")
    String doIt(String s1, int i2);

    String getString(Object arg1, @Filter Set<Object> keys);

}

預設情況下,Function ID 是簡單的(非限定的)方法名。@FunctionId 註解可用於將此呼叫繫結到不同的 Function ID。

11.3.2. 啟用註解處理

客戶端使用 Spring 的 classpath 元件掃描功能來發現帶註解的介面。要在 XML 中啟用 Function 執行註解處理,請在 XML 配置中插入以下元素

<gfe-data:function-executions base-package="org.example.myapp.gemfire.functions"/>

function-executions 元素在 gfe-data XML 名稱空間中提供。base-package 屬性是必需的,以避免掃描整個 classpath。可以提供額外的過濾器,如 Spring 參考文件中所述。

或者,您可以按如下方式註解您的 Java 配置類

@EnableGemfireFunctionExecutions(basePackages = "org.example.myapp.gemfire.functions")

11.4. 程式設計式函式執行

使用上一節中定義的 Function 執行註解介面,只需將您的介面自動裝配到將呼叫 Function 的應用程式 bean 中

@Component
public class MyApplication {

    @Autowired
    FunctionExecution functionExecution;

    public void doSomething() {
         functionExecution.doIt("hello", 123);
    }
}

或者,您可以直接使用 Function 執行模板。在以下示例中,GemfireOnRegionFunctionTemplate 建立了一個 onRegion Function Execution

示例 19. 使用 GemfireOnRegionFunctionTemplate
Set<?, ?> myFilter = getFilter();
Region<?, ?> myRegion = getRegion();
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(myRegion);
String result = template.executeAndExtract("someFunction", myFilter, "hello", "world", 1234);

在內部,Function Executions 始終返回一個 ListexecuteAndExtract 假設一個包含結果的單例 List 並嘗試將該值強制轉換為請求的型別。還有一個 execute 方法返回原樣的 List。第一個引數是 Function ID。過濾器引數是可選的。其餘引數是可變引數 List

11.5. 使用 PDX 執行函式

當使用 Spring Data for Pivotal GemFire 的 Function 註解支援結合 Pivotal GemFire 的 PDX 序列化時,需要牢記一些邏輯事項。

如本節前面所解釋的,並以示例說明,您通常應使用帶有 Spring Data for Pivotal GemFire Function 註解的 POJO 類來定義 Pivotal GemFire Functions,如下所示

public class OrderFunctions {

  @GemfireFunction(...)
  Order process(@RegionData data, Order order, OrderSource orderSourceEnum, Integer count) { ... }

}
Integer 型別的 count 引數是任意的,Order 類和 OrderSource 列舉的分離也是任意的,它們在邏輯上可能應該合併。但是,引數以這種方式設定是為了演示在 PDX 上下文中 Function 執行的問題。

您的 Order 類和 OrderSource 列舉可能定義如下

public class Order ... {

  private Long orderNumber;
  private LocalDateTime orderDateTime;
  private Customer customer;
  private List<Item> items

  ...
}


public enum OrderSource {
  ONLINE,
  PHONE,
  POINT_OF_SALE
  ...
}

當然,您可以定義一個 Function Execution 介面來呼叫“process” Pivotal GemFire 伺服器 Function,如下所示

@OnServer
public interface OrderProcessingFunctions {
  Order process(Order order, OrderSource orderSourceEnum, Integer count);
}

顯然,這個 process(..) Order Function 是從客戶端使用 ClientCache 例項(即 <gfe:client-cache/>)呼叫的。這意味著 Function 引數也必須是可序列化的。在叢集中呼叫對等成員 Function(例如 @OnMember(s))時也是如此。任何形式的 distribution 都要求客戶端和伺服器(或對等體)之間傳輸的資料是可序列化的。

現在,如果您已將 Pivotal GemFire 配置為使用 PDX 進行序列化(例如,而不是 Java 序列化),您還可以在 Pivotal GemFire 伺服器的配置中將 pdx-read-serialized 屬性設定為 true,如下所示

<gfe:cache ... pdx-read-serialized="true"/>

或者,您可以為 Pivotal GemFire 快取客戶端應用程式將 pdx-read-serialized 屬性設定為 true,如下所示

<gfe:client-cache ... pdx-read-serialized="true"/>

這樣做會導致從快取(即 Regions)讀取的所有值以及在客戶端和伺服器(或對等體)之間傳遞的資訊保持序列化形式,包括但不限於 Function 引數。

Pivotal GemFire 僅序列化您透過使用 Pivotal GemFire 的 ReflectionBasedAutoSerializer 明確配置(註冊)的應用程式域物件型別,或者透過使用“自定義” Pivotal GemFire PdxSerializer 明確配置(並推薦)的應用程式域物件型別。如果您使用 Spring Data for Pivotal GemFire 的 Repository 擴充套件,您甚至可能希望考慮使用 Spring Data for Pivotal GemFire 的 MappingPdxSerializer,它使用實體對映元資料來確定從應用程式域物件序列化到 PDX 例項的資料。

然而,不那麼明顯的是,Pivotal GemFire 自動處理 Java Enum 型別,無論它們是否明確配置(即,使用正則表示式模式和 classes 引數註冊到 ReflectionBasedAutoSerializer,或者由“自定義” Pivotal GemFire PdxSerializer 處理),儘管 Java 列舉實現了 java.io.Serializable

因此,當您在註冊 Pivotal GemFire Functions(包括 Spring Data for Pivotal GemFire Function 註解的 POJO 類)的 Pivotal GemFire 伺服器上將 pdx-read-serialized 設定為 true 時,您在呼叫 Function Execution 時可能會遇到令人驚訝的行為。

您在呼叫 Function 時可能會傳遞以下引數

orderProcessingFunctions.process(new Order(123, customer, LocalDateTime.now(), items), OrderSource.ONLINE, 400);

然而,伺服器上的 Pivotal GemFire Function 得到以下結果

process(regionData, order:PdxInstance, :PdxInstanceEnum, 400);

OrderOrderSource 已作為 PDX 例項傳遞給 Function。同樣,所有這些都發生是因為 pdx-read-serialized 設定為 true,這在 Pivotal GemFire 伺服器與多個不同客戶端(例如,Java 客戶端和原生客戶端(如 C/C++、C# 等)的組合)互動的情況下可能是必要的。

這與 Spring Data for Pivotal GemFire 的強型別 Function 註解 POJO 類方法簽名背道而馳,在該簽名中,您通常會合理地期望應用程式域物件型別,而不是 PDX 序列化例項。

因此,Spring Data for Pivotal GemFire 包含了增強的 Function 支援,以自動將 PDX 型別的方法引數轉換為 Function 方法簽名(引數型別)定義的所需應用程式域物件型別。

然而,這還要求您在註冊和使用 Spring Data for Pivotal GemFire Function 註解 POJO 的 Pivotal GemFire 伺服器上明確註冊一個 Pivotal GemFire PdxSerializer,如下例所示

<bean id="customPdxSerializer" class="x.y.z.gemfire.serialization.pdx.MyCustomPdxSerializer"/>

<gfe:cache ... pdx-serializer-ref="customPdxSerializeer" pdx-read-serialized="true"/>

或者,為了方便起見,您可以使用 Pivotal GemFire 的 ReflectionBasedAutoSerializer。當然,我們建議在可能的情況下,您使用自定義 PdxSerializer 來保持對序列化策略的更精細控制。

最後,Spring Data for Pivotal GemFire 會小心地不轉換您的 Function 引數,如果您將 Function 引數視為泛型或 Pivotal GemFire 的 PDX 型別之一,如下所示

@GemfireFunction
public Object genericFunction(String value, Object domainObject, PdxInstanceEnum enum) {
 ...
}

Spring Data for Pivotal GemFire 僅當相應的應用程式域型別在 classpath 中且 Function 註解的 POJO 方法期望它時,才會將 PDX 型別資料轉換為相應的應用程式域型別。

有關自定義、組合的應用程式特定 Pivotal GemFire PdxSerializers 以及基於方法簽名的適當 POJO Function 引數型別處理的良好示例,請參見 Spring Data for Pivotal GemFire 的 ClientCacheFunctionExecutionWithPdxIntegrationTest 類。

12. Apache Lucene 整合

Pivotal GemFireApache Lucene 整合,讓您可以使用 Lucene 查詢索引和搜尋儲存在 Pivotal GemFire 中的資料。基於搜尋的查詢還包括分頁查詢結果的能力。

此外,Spring Data for Pivotal GemFire 添加了對基於 Spring Data Commons 投影基礎設施的查詢投影的支援。此功能允許根據應用程式的需要將查詢結果投影到一流的應用程式域型別中。

在執行任何基於 Lucene 搜尋的查詢之前,必須建立 Lucene Index。可以在 Spring (Data for Pivotal GemFire) XML 配置中建立 LuceneIndex,如下所示

<gfe:lucene-index id="IndexOne" fields="fieldOne, fieldTwo" region-path="/Example"/>

此外,Apache Lucene 允許為每個欄位指定 分析器,並且可以按以下示例所示進行配置

<gfe:lucene-index id="IndexTwo" lucene-service-ref="luceneService" region-path="/AnotherExample">
    <gfe:field-analyzers>
        <map>
            <entry key="fieldOne">
                <bean class="example.AnalyzerOne"/>
             </entry>
            <entry key="fieldTwo">
                <bean class="example.AnalyzerTwo"/>
             </entry>
        </map>
    </gfe:field-analyzers>
</gfe:lucene-index>

Map 可以指定為頂級 bean 定義,並透過巢狀的 <gfe:field-analyzers> 元素中的 ref 屬性引用,如下所示:<gfe-field-analyzers ref="refToTopLevelMapBeanDefinition"/>

Spring Data for Pivotal GemFire 的 LuceneIndexFactoryBean API 和 SDG 的 XML 名稱空間還允許在建立 LuceneIndex 時指定 org.apache.geode.cache.lucene.LuceneSerializerLuceneSerializer 允許您配置物件在索引時如何轉換為 Lucene 文件。

以下示例演示瞭如何向 LuceneIndex 新增 LuceneSerializer

<bean id="MyLuceneSerializer" class="example.CustomLuceneSerializer"/>

<gfe:lucene-index id="IndexThree" lucene-service-ref="luceneService" region-path="/YetAnotherExample">
    <gfe:lucene-serializer ref="MyLuceneSerializer">
</gfe:lucene-index>

您還可以將 LuceneSerializer 指定為匿名巢狀 bean 定義,如下所示

<gfe:lucene-index id="IndexThree" lucene-service-ref="luceneService" region-path="/YetAnotherExample">
    <gfe:lucene-serializer>
        <bean class="example.CustomLuceneSerializer"/>
    </gfe:lucene-serializer>
</gfe:lucene-index>

或者,您可以在 Spring Java 配置中,在 @Configuration 類中宣告或定義 LuceneIndex,如下例所示

@Bean(name = "Books")
@DependsOn("bookTitleIndex")
PartitionedRegionFactoryBean<Long, Book> booksRegion(GemFireCache gemfireCache) {

    PartitionedRegionFactoryBean<Long, Book> peopleRegion =
        new PartitionedRegionFactoryBean<>();

    peopleRegion.setCache(gemfireCache);
    peopleRegion.setClose(false);
    peopleRegion.setPersistent(false);

    return peopleRegion;
}

@Bean
LuceneIndexFactoryBean bookTitleIndex(GemFireCache gemFireCache,
        LuceneSerializer luceneSerializer) {

    LuceneIndexFactoryBean luceneIndex = new LuceneIndexFactoryBean();

    luceneIndex.setCache(gemFireCache);
    luceneIndex.setFields("title");
    luceneIndex.setLuceneSerializer(luceneSerializer);
    luceneIndex.setRegionPath("/Books");

    return luceneIndex;
}

@Bean
CustomLuceneSerializer myLuceneSerialier() {
    return new CustomeLuceneSerializer();
}

Pivotal GemFire 的 Apache Lucene 整合和支援有一些限制。

首先,LuceneIndex 只能在 Pivotal GemFire PARTITION Region 上建立。

其次,所有 LuceneIndexes 必須在 LuceneIndex 所適用的 Region 之前建立。

為了幫助確保 Spring 容器中定義的所有宣告的 LuceneIndexes 在其適用的 Region 之前建立,SDG 包含 org.springframework.data.gemfire.config.support.LuceneIndexRegionBeanFactoryPostProcessor。您可以使用 <bean class="org.springframework.data.gemfire.config.support.LuceneIndexRegionBeanFactoryPostProcessor"/> 在 XML 配置中註冊此 Spring BeanFactoryPostProcessoro.s.d.g.config.support.LuceneIndexRegionBeanFactoryPostProcessor 只能在使用 SDG XML 配置時使用。有關 Spring 的 BeanFactoryPostProcessors 的更多詳細資訊可以在此處找到。

Pivotal GemFire 的這些限制在未來的版本中可能不會適用,這也是 SDG LuceneIndexFactoryBean API 直接引用 Region 而不僅僅是 Region 路徑的原因。

當您希望在應用程式生命週期的後期以及需求要求時,在具有資料的現有 Region 上定義 LuceneIndex 時,這更為理想。在可能的情況下,SDG 努力遵守強型別物件。但是,目前,您必須使用 regionPath 屬性來指定 LuceneIndex 應用的 Region。

此外,在前面的示例中,請注意 Books Region bean 定義上存在 Spring 的 @DependsOn 註解。這會建立從 Books Region bean 到 bookTitleIndex LuceneIndex bean 定義的依賴關係,確保在 Region 之前建立 LuceneIndex

現在我們有了 LuceneIndex,我們可以執行基於 Lucene 的資料訪問操作,例如查詢。

12.1. Lucene 模板資料訪問器

Spring Data for Pivotal GemFire 提供了兩個主要的 Lucene 資料訪問操作模板,具體取決於您的應用程式願意處理的級別。

LuceneOperations 介面使用 Pivotal GemFire Lucene 型別定義查詢操作,這些型別在以下介面定義中定義

public interface LuceneOperations {

    <K, V> List<LuceneResultStruct<K, V>> query(String query, String defaultField [, int resultLimit]
        , String... projectionFields);

    <K, V> PageableLuceneQueryResults<K, V> query(String query, String defaultField,
        int resultLimit, int pageSize, String... projectionFields);

    <K, V> List<LuceneResultStruct<K, V>> query(LuceneQueryProvider queryProvider [, int resultLimit]
        , String... projectionFields);

    <K, V> PageableLuceneQueryResults<K, V> query(LuceneQueryProvider queryProvider,
        int resultLimit, int pageSize, String... projectionFields);

    <K> Collection<K> queryForKeys(String query, String defaultField [, int resultLimit]);

    <K> Collection<K> queryForKeys(LuceneQueryProvider queryProvider [, int resultLimit]);

    <V> Collection<V> queryForValues(String query, String defaultField [, int resultLimit]);

    <V> Collection<V> queryForValues(LuceneQueryProvider queryProvider [, int resultLimit]);
}
[, int resultLimit] 表示 resultLimit 引數是可選的。

LuceneOperations 介面中的操作與 Pivotal GemFire 的 LuceneQuery 介面提供的操作相匹配。但是,SDG 的附加價值在於將專有的 Pivotal GemFire 或 Apache Lucene Exceptions 轉換為 Spring 的高度一致和富有表現力的 DAO 異常層次結構,特別是當許多現代資料訪問操作涉及多個儲存或儲存庫時。

此外,當底層 Pivotal GemFire 或 Apache Lucene API 引入破壞介面的更改時,SDG 的 LuceneOperations 介面可以保護您的應用程式免受這些更改的影響。

然而,如果僅使用 Pivotal GemFire 和 Apache Lucene 資料型別(例如 Pivotal GemFire 的 LuceneResultStruct)提供 Lucene 資料訪問物件(DAO)會很遺憾。因此,SDG 為您提供了 ProjectingLuceneOperations 介面來解決這些重要的應用程式問題。以下清單顯示了 ProjectingLuceneOperations 介面定義

public interface ProjectingLuceneOperations {

    <T> List<T> query(String query, String defaultField [, int resultLimit], Class<T> projectionType);

    <T> Page<T> query(String query, String defaultField, int resultLimit, int pageSize, Class<T> projectionType);

    <T> List<T> query(LuceneQueryProvider queryProvider [, int resultLimit], Class<T> projectionType);

    <T> Page<T> query(LuceneQueryProvider queryProvider, int resultLimit, int pageSize, Class<T> projectionType);
}

ProjectingLuceneOperations 介面主要使用應用程式域物件型別,讓您可以使用應用程式資料。query 方法變體接受一個投影型別,模板使用 Spring Data Commons Projection 基礎設施將查詢結果應用於給定投影型別的例項。

此外,模板將分頁的 Lucene 查詢結果包裝在 Spring Data Commons Page 抽象的例項中。相同的投影邏輯仍然可以應用於頁面中的結果,並且在訪問集合中的每個頁面時進行惰性投影。

例如,假設您有一個表示 Person 的類,如下所示

class Person {

    Gender gender;

    LocalDate birthDate;

    String firstName;
    String lastName;

    ...

    String getName() {
        return String.format("%1$s %2$s", getFirstName(), getLastName());
    }
}

此外,根據您的應用程式檢視,您可能有一個單獨的介面來表示人員為 Customers,如下所示

interface Customer {

    String getName()

}

如果我定義以下 LuceneIndex……

@Bean
LuceneIndexFactoryBean personLastNameIndex(GemFireCache gemfireCache) {

    LuceneIndexFactoryBean personLastNameIndex =
        new LuceneIndexFactoryBean();

    personLastNameIndex.setCache(gemfireCache);
    personLastNameIndex.setFields("lastName");
    personLastNameIndex.setRegionPath("/People");

    return personLastNameIndex;
}

那麼您可以查詢人員作為 Person 物件,如下所示

List<Person> people = luceneTemplate.query("lastName: D*", "lastName", Person.class);

或者,您可以查詢 Customer 型別的 Page,如下所示

Page<Customer> customers = luceneTemplate.query("lastName: D*", "lastName", 100, 20, Customer.class);

然後可以使用 Page 來獲取結果的各個頁面,如下所示

List<Customer> firstPage = customers.getContent();

方便的是,Spring Data Commons Page 介面還實現了 java.lang.Iterable<T>,使其易於遍歷內容。

Spring Data Commons Projection 基礎設施的唯一限制是投影型別必須是介面。但是,可以擴充套件提供的 SDC Projection 基礎設施並提供一個使用 CGLIB 生成代理類作為投影實體的自定義 ProjectionFactory

您可以使用 setProjectionFactory(:ProjectionFactory) 在 Lucene 模板上設定自定義 ProjectionFactory

12.2. 註解配置支援

最後,Spring Data for Pivotal GemFire 為 LuceneIndexes 提供了註解配置支援。

最終,SDG Lucene 支援將進入 Pivotal GemFire 的 Repository 基礎設施擴充套件,以便 Lucene 查詢可以像 OQL 支援今天的工作方式一樣,在應用程式 Repository 介面上表示為方法。

但是,與此同時,如果您想方便地表達 LuceneIndexes,您可以直接在應用程式域物件上進行,如下例所示

@PartitionRegion("People")
class Person {

    Gender gender;

    @Index
    LocalDate birthDate;

    String firstName;

    @LuceneIndex;
    String lastName;

    ...
}

要啟用此功能,您必須使用 SDG 的註解配置支援,特別是 @EnableEntityDefineRegions@EnableIndexing 註解,如下所示

@PeerCacheApplication
@EnableEntityDefinedRegions
@EnableIndexing
class ApplicationConfiguration {

  ...
}
LuceneIndexes 只能在 Pivotal GemFire 伺服器上建立,因為 LuceneIndexes 僅適用於 PARTITION Regions。

鑑於我們前面定義的 Person 類,SDG 註解配置支援會找到 Person 實體類定義,並確定人員儲存在名為“People”的 PARTITION Region 中,並且 PersonbirthDate 上有一個 OQL Index,在 lastName 上有一個 LuceneIndex

13. 在 Pivotal GemFire 中引導 Spring ApplicationContext

通常,基於 Spring 的應用程式使用 Spring Data for Pivotal GemFire 的功能來引導 Pivotal GemFire。透過指定使用 Spring Data for Pivotal GemFire XML 名稱空間的 <gfe:cache/> 元素,將在與應用程式相同的 JVM 程序中建立並初始化一個具有預設設定的單個嵌入式 Pivotal GemFire 對等 Cache 例項。

然而,有時有必要(也許是您的 IT 組織強制要求)Pivotal GemFire 由提供的 Pivotal GemFire 工具套件完全管理和操作,可能使用 Gfsh。透過使用 Gfsh,Pivotal GemFire 引導您的 Spring ApplicationContext,而不是相反。Pivotal GemFire 負責引導並託管您的應用程式,而不是應用程式伺服器或使用 Spring Boot 的 Java main 類。

Pivotal GemFire 不是應用程式伺服器。此外,在使用此方法時,Pivotal GemFire 快取配置方面存在限制。

13.1. 使用 Pivotal GemFire 引導透過 Gfsh 啟動的 Spring Context

為了在透過 Gfsh 啟動 Pivotal GemFire 伺服器時引導 Pivotal GemFire 中的 Spring ApplicationContext,您必須使用 Pivotal GemFire 的 初始化器 功能。初始化器塊可以宣告一個應用程式回撥,該回調在快取由 Pivotal GemFire 初始化後啟動。

初始化器在 初始化器 元素中宣告,使用 Pivotal GemFire 原生 cache.xml 的最小程式碼片段。為了引導 Spring ApplicationContext,需要一個 cache.xml 檔案,這與引導配置了元件掃描的 Spring ApplicationContext(例如 <context:component-scan base-packages="…​"/>)所需的最小 Spring XML 配置程式碼片段非常相似。

幸運的是,框架已經方便地提供了這樣的初始化器:SpringContextBootstrappingInitializer

以下示例展示了此類的典型但最小化的配置,位於 Pivotal GemFire 的 cache.xml 檔案中

<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="http://geode.apache.org/schema/cache"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://geode.apache.org/schema/cache https://geode.apache.org/schema/cache/cache-1.0.xsd"
       version="1.0">

  <initializer>
    <class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer</class-name>
    <parameter name="contextConfigLocations">
      <string>classpath:application-context.xml</string>
    </parameter>
  </initializer>

</cache>

SpringContextBootstrappingInitializer 類遵循與 Spring 的 ContextLoaderListener 類類似的約定,ContextLoaderListener 類用於在 Web 應用程式中引導 Spring ApplicationContext,其中 ApplicationContext 配置檔案由 contextConfigLocations Servlet 上下文引數指定。

此外,SpringContextBootstrappingInitializer 類還可以與 basePackages 引數一起使用,以指定包含適當註解的應用程式元件的逗號分隔的基本包列表。Spring 容器搜尋這些元件以在 classpath 中查詢和建立 Spring bean 和其他應用程式元件,如下例所示

<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="http://geode.apache.org/schema/cache"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://geode.apache.org/schema/cache https://geode.apache.org/schema/cache/cache-1.0.xsd"
       version="1.0">

  <initializer>
    <class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer</class-name>
    <parameter name="basePackages">
      <string>org.mycompany.myapp.services,org.mycompany.myapp.dao,...</string>
    </parameter>
  </initializer>

</cache>

然後,當在 Gfsh 中啟動 Pivotal GemFire 伺服器時,將正確配置和構造的 CLASSPATHcache.xml 檔案(前面所示)指定為命令列選項,命令列將如下所示

gfsh>start server --name=ExampleServer --log-level=config ...
    --classpath="/path/to/application/classes.jar:/path/to/spring-data-geode-<major>.<minor>.<maint>.RELEASE.jar"
    --cache-xml-file="/path/to/geode/cache.xml"

application-context.xml 可以是任何有效的 Spring 配置元資料,包括所有 SDG XML 名稱空間元素。此方法的唯一限制是無法使用 SDG XML 名稱空間配置 Pivotal GemFire 快取。換句話說,不能指定任何 <gfe:cache/> 元素屬性(例如 cache-xml-locationproperties-refcritical-heap-percentagepdx-serializer-reflock-lease 等)。如果使用,這些屬性將被忽略。

原因在於 Pivotal GemFire 本身在初始化器被呼叫之前就已經建立並初始化了快取。因此,快取已經存在,並且由於它是一個“單例”,它不能被重新初始化或對其任何配置進行增強。

13.2. 惰性連線 Pivotal GemFire 元件

Spring Data for Pivotal GemFire 已經支援透過使用 SDG 的 WiringDeclarableSupport 類在 cache.xml 中宣告和建立的 Pivotal GemFire 元件(例如 CacheListenersCacheLoadersCacheWriters 等)的自動裝配,如使用自動裝配和註解進行配置中所述。但是,這僅在 Spring 進行引導時(即當 Spring 引導 Pivotal GemFire 時)才有效。

當您的 Spring ApplicationContext 由 Pivotal GemFire 引導時,這些 Pivotal GemFire 應用程式元件將不被注意,因為 Spring ApplicationContext 尚不存在。直到 Pivotal GemFire 呼叫初始化器塊,Spring ApplicationContext 才會被建立,而這僅在所有其他 Pivotal GemFire 元件(快取、Region 等)都已建立和初始化之後才發生。

為了解決這個問題,引入了新的 LazyWiringDeclarableSupport 類。這個新類感知 Spring ApplicationContext。這個抽象基類的目的是讓任何實現類註冊自己,以便在初始化器被呼叫後,最終由 Pivotal GemFire 建立的 Spring 容器進行配置。本質上,這讓您的 Pivotal GemFire 應用程式元件有機會透過 Spring 容器中定義的 Spring bean 進行配置和自動裝配。

為了讓您的 Pivotal GemFire 應用程式元件由 Spring 容器自動裝配,您應該建立一個擴充套件 LazyWiringDeclarableSupport 的應用程式類,並註解任何需要作為 Spring bean 依賴項提供的類成員,類似於以下示例

public class UserDataSourceCacheLoader extends LazyWiringDeclarableSupport
    implements CacheLoader<String, User> {

  @Autowired
  private DataSource userDataSource;

  ...
}

如上文 CacheLoader 示例所示,您可能需要(儘管很少)在 Pivotal GemFire cache.xml 中同時定義 Region 和 CacheListener 元件。CacheLoader 可能需要訪問應用程式儲存庫(或 Spring ApplicationContext 中定義的 JDBC DataSource)才能在啟動時將 Users 載入到 Pivotal GemFire REPLICATE Region 中。

注意

以這種方式混合 Pivotal GemFire 和 Spring 容器的不同生命週期時要小心。並非所有用例和場景都受支援。Pivotal GemFire cache.xml 配置將類似於以下內容(來自 SDG 的測試套件)

<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="http://geode.apache.org/schema/cache"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://geode.apache.org/schema/cache https://geode.apache.org/schema/cache/cache-1.0.xsd"
       version="1.0">

  <region name="Users" refid="REPLICATE">
    <region-attributes initial-capacity="101" load-factor="0.85">
      <key-constraint>java.lang.String</key-constraint>
      <value-constraint>org.springframework.data.gemfire.repository.sample.User</value-constraint>
      <cache-loader>
        <class-name>
          org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerIntegrationTest$UserDataStoreCacheLoader
        </class-name>
      </cache-loader>
    </region-attributes>
  </region>

  <initializer>
    <class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer</class-name>
    <parameter name="basePackages">
      <string>org.springframework.data.gemfire.support.sample</string>
    </parameter>
  </initializer>

</cache>

14. 示例應用程式

示例應用程式現在在 Spring Pivotal GemFire Examples 儲存庫中維護。

Spring Data for Pivotal GemFire 專案還包括一個示例應用程式。該示例應用程式名為“Hello World”,演示瞭如何在 Spring 應用程式中配置和使用 Pivotal GemFire。在執行時,該示例提供了一個 Shell,讓您可以對資料網格執行各種命令。它為不熟悉基本元件或 Spring 和 Pivotal GemFire 概念的開發人員提供了一個極好的起點。

該示例與分發包捆綁在一起,並且是基於 Maven 的。您可以將其匯入任何支援 Maven 的 IDE(例如 Spring Tool Suite)或從命令列執行它們。

14.1. Hello World

“Hello World”示例應用程式演示了 Spring Data for Pivotal GemFire 專案的核心功能。它引導 Pivotal GemFire,配置它,對快取執行任意命令,並在應用程式退出時將其關閉。可以同時啟動多個應用程式例項並協同工作,無需任何使用者干預即可共享資料。

在 Linux 下執行
如果在啟動 Pivotal GemFire 或示例時遇到網路問題,請嘗試向命令列新增以下系統屬性 java.net.preferIPv4Stack=true(例如,-Djava.net.preferIPv4Stack=true)。有關替代(全域性)修復(尤其是在 Ubuntu 上),請參閱 SGF-28

14.1.1. 啟動和停止示例

“Hello World”示例應用程式設計為獨立的 Java 應用程式。它具有一個 main 類,可以從您的 IDE(在 Eclipse 或 STS 中,透過 Run As/Java Application)或透過 Maven 命令列使用 mvn exec:java 啟動。如果 classpath 設定正確,您還可以直接對生成的 artifact 使用 java

要停止示例,請在命令列鍵入 exit 或按 Ctrl+C 以停止 JVM 並關閉 Spring 容器。

14.1.2. 使用示例

一旦啟動,示例將建立一個共享資料網格,並允許您對其釋出命令。輸出應類似於以下內容

INFO: Created {data-store-name} Cache [Spring {data-store-name} World] v. X.Y.Z
INFO: Created new cache region [myWorld]
INFO: Member xxxxxx:50694/51611 connecting to region [myWorld]
Hello World!
Want to interact with the world ? ...
Supported commands are:

get <key> - retrieves an entry (by key) from the grid
put <key> <value> - puts a new entry into the grid
remove <key> - removes an entry (by key) from the grid
...

例如,要向網格新增新項,可以使用以下命令

-> Bold Section qName:emphasis level:5, chunks:[put 1 unu] attrs:[role:bold]
INFO: Added [1=unu] to the cache
null
-> Bold Section qName:emphasis level:5, chunks:[put 1 one] attrs:[role:bold]
INFO: Updated [1] from [unu] to [one]
unu
-> Bold Section qName:emphasis level:5, chunks:[size] attrs:[role:bold]
1
-> Bold Section qName:emphasis level:5, chunks:[put 2 two] attrs:[role:bold]
INFO: Added [2=two] to the cache
null
-> Bold Section qName:emphasis level:5, chunks:[size] attrs:[role:bold]
2

可以同時執行多個例項。一旦啟動,新的 VM 會自動看到現有區域及其資訊,如下例所示

INFO: Connected to Distributed System ['Spring {data-store-name} World'=xxxx:56218/49320@yyyyy]
Hello World!
...

-> Bold Section qName:emphasis level:5, chunks:[size] attrs:[role:bold]
2
-> Bold Section qName:emphasis level:5, chunks:[map] attrs:[role:bold]
[2=two] [1=one]
-> Bold Section qName:emphasis level:5, chunks:[query length = 3] attrs:[role:bold]
[one, two]

我們鼓勵您嘗試該示例,啟動(和停止)任意數量的例項,並在一個例項中執行各種命令,並觀察其他例項如何響應。為了保留資料,至少一個例項需要始終保持活動狀態。如果所有例項都關閉,則網格資料將完全銷燬。

14.1.3. Hello World 示例說明

“Hello World”示例使用 Spring XML 和註解進行配置。初始引導配置是 app-context.xml,它包含在 cache-context.xml 檔案中定義的快取配置,並對 Spring 元件執行 classpath 元件掃描

快取配置定義了 Pivotal GemFire 快取、一個區域以及出於說明目的,一個充當日誌記錄器的 CacheListener

主要的 bean 是 HelloWorldCommandProcessor,它們依賴於 GemfireTemplate 與分散式結構互動。這兩個類都使用註解來定義它們的依賴項和生命週期回撥。

資源

除了本文件外,還有許多其他資源可以幫助您學習如何將 {data-store-product-name} 與 Spring Framework 一起使用。這些額外的第三方資源在本節中列出。

附錄

附錄 A: 名稱空間參考

<repositories /> 元素

<repositories /> 元素觸發 Spring Data 儲存庫基礎設施的設定。最重要的屬性是 base-package,它定義了要掃描 Spring Data 儲存庫介面的包。請參閱“[repositories.create-instances.spring]”。下表描述了 <repositories /> 元素的屬性

表 6. 屬性
名稱 描述

base-package

定義在自動檢測模式下掃描擴充套件 *Repository(實際介面由特定的 Spring Data 模組確定)的倉庫介面的包。配置包下的所有包也都會被掃描。允許使用萬用字元。

repository-impl-postfix

定義自動檢測自定義倉庫實現的字尾。名稱以配置的字尾結尾的類被視為候選。預設為 Impl

query-lookup-strategy

確定用於建立查詢查詢的策略。有關詳細資訊,請參閱“[repositories.query-methods.query-lookup-strategies]”。預設為 create-if-not-found

named-queries-location

定義搜尋包含外部定義查詢的 Properties 檔案的位置。

consider-nested-repositories

是否應考慮巢狀倉庫介面定義。預設為 false

附錄 B: Populators 名稱空間參考

<populator /> 元素

<populator /> 元素允許透過 Spring Data 儲存庫基礎設施填充資料儲存。[1]

表 7. 屬性
名稱 描述

locations

從何處查詢檔案以讀取要填充倉庫的物件。

附錄 C: 儲存庫查詢關鍵字

支援的查詢關鍵字

下表列出了 Spring Data 儲存庫查詢派生機制通常支援的關鍵字。但是,請查閱特定儲存的文件,以獲取受支援關鍵字的確切列表,因為此處列出的一些關鍵字可能不受特定儲存的支援。

表 8. 查詢關鍵字
邏輯關鍵字 關鍵字表達式

AND

And

OR

Or

AFTER

After, IsAfter

BEFORE

Before, IsBefore

CONTAINING

Containing, IsContaining, Contains

BETWEEN

Between, IsBetween

ENDING_WITH

EndingWith, IsEndingWith, EndsWith

EXISTS

Exists

FALSE

False, IsFalse

GREATER_THAN

GreaterThan, IsGreaterThan

GREATER_THAN_EQUALS

GreaterThanEqual, IsGreaterThanEqual

IN

In, IsIn

IS

Is, Equals, (或沒有關鍵字)

IS_EMPTY

IsEmpty, Empty

IS_NOT_EMPTY

IsNotEmpty, NotEmpty

IS_NOT_NULL

NotNull, IsNotNull

IS_NULL

Null, IsNull

LESS_THAN

LessThan, IsLessThan

LESS_THAN_EQUAL

LessThanEqual, IsLessThanEqual

LIKE

Like, IsLike

NEAR

Near, IsNear

NOT

Not, IsNot

NOT_IN

NotIn, IsNotIn

NOT_LIKE

NotLike, IsNotLike

REGEX

Regex, MatchesRegex, Matches

STARTING_WITH

StartingWith, IsStartingWith, StartsWith

TRUE

True, IsTrue

WITHIN

Within, IsWithin

附錄 D: 儲存庫查詢返回型別

支援的查詢返回型別

下表列出了 Spring Data 倉庫通常支援的返回型別。但是,請查閱特定於儲存的文件以獲取支援返回型別的確切列表,因為此處列出的一些型別可能在特定儲存中不受支援。

地理空間型別(例如 GeoResultGeoResultsGeoPage)僅適用於支援地理空間查詢的資料儲存。
表 9. 查詢返回型別
返回型別 描述

void

表示無返回值。

Primitives

Java 基本型別。

Wrapper types

Java 包裝型別。

T

一個唯一的實體。期望查詢方法最多返回一個結果。如果未找到結果,則返回 null。超過一個結果會觸發 IncorrectResultSizeDataAccessException

Iterator<T>

一個 Iterator

Collection<T>

一個 Collection

List<T>

一個 List

Optional<T>

一個 Java 8 或 Guava Optional。期望查詢方法最多返回一個結果。如果未找到結果,則返回 Optional.empty()Optional.absent()。超過一個結果會觸發 IncorrectResultSizeDataAccessException

Option<T>

Scala 或 Vavr Option 型別。語義上與 Java 8 的 Optional 行為相同,如前所述。

Stream<T>

一個 Java 8 Stream

Streamable<T>

Iterable 的便利擴充套件,直接公開了用於流式傳輸、對映和過濾結果、連線它們等方法。

實現 Streamable 並接受 Streamable 建構函式或工廠方法引數的型別

公開帶有 Streamable 作為引數的建構函式或 ….of(…)/….valueOf(…) 工廠方法的型別。有關詳細資訊,請參閱[repositories.collections-and-iterables.streamable-wrapper]

Vavr Seq, List, Map, Set

Vavr 集合型別。有關詳細資訊,請參閱[repositories.collections-and-iterables.vavr]

Future<T>

一個 Future。期望方法使用 @Async 註解,並要求啟用 Spring 的非同步方法執行功能。

CompletableFuture<T>

一個 Java 8 CompletableFuture。期望方法使用 @Async 註解,並要求啟用 Spring 的非同步方法執行功能。

ListenableFuture

一個 org.springframework.util.concurrent.ListenableFuture。期望方法用 @Async 註解,並要求啟用 Spring 的非同步方法執行功能。

Slice

一個帶大小的資料塊,並指示是否有更多資料可用。需要一個 Pageable 方法引數。

Page<T>

一個 Slice 帶有附加資訊,例如總結果數。需要一個 Pageable 方法引數。

GeoResult<T>

一個結果條目,帶有附加資訊,例如到參考位置的距離。

GeoResults<T>

一個 GeoResult<T> 列表,帶有附加資訊,例如到參考位置的平均距離。

GeoPage<T>

一個帶有 GeoResult<T>Page,例如到參考位置的平均距離。

Mono<T>

使用響應式倉庫時,Project Reactor Mono 發出零個或一個元素。期望查詢方法最多返回一個結果。如果未找到結果,則返回 Mono.empty()。多於一個結果會觸發 IncorrectResultSizeDataAccessException

Flux<T>

使用響應式倉庫時,Project Reactor Flux 發出零個、一個或多個元素。返回 Flux 的查詢也可以發出無限數量的元素。

Single<T>

使用響應式倉庫時,RxJava Single 發出一個元素。期望查詢方法最多返回一個結果。如果未找到結果,則返回 Mono.empty()。多於一個結果會觸發 IncorrectResultSizeDataAccessException

Maybe<T>

使用響應式倉庫時,RxJava Maybe 發出零個或一個元素。期望查詢方法最多返回一個結果。如果未找到結果,則返回 Mono.empty()。多於一個結果會觸發 IncorrectResultSizeDataAccessException

Flowable<T>

使用響應式倉庫時,RxJava Flowable 發出零個、一個或多個元素。返回 Flowable 的查詢也可以發出無限數量的元素。

附錄 E: Spring Data for Pivotal GemFire 架構


1. 參見[repositories.create-instances.spring]
© . This site is unofficial and not affiliated with VMware.