© 2010-2019 原始作者。

本檔案的副本可供您自己使用,也可分發給其他人,前提是您不對此類副本收取任何費用,並且無論以印刷版還是電子版分發,每個副本都包含此版權宣告。

前言

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

本文件假設您已經對核心 Spring Framework 和 Pivotal GemFire 概念有了基本的瞭解和一些熟悉。

雖然已盡一切努力確保本檔案全面、完整且無錯誤,但某些主題超出了本檔案的範圍,可能需要更多解釋(例如,在保持一致性的同時使用分割槽進行資料分佈管理和高可用性)。此外,還可能出現一些印刷錯誤。如果您發現錯誤甚至更嚴重的錯誤,請透過在 JIRA 中提出適當的 問題,將這些問題告知 Spring Data 團隊。

1. 簡介

Pivotal GemFire 的 Spring Data 參考指南解釋瞭如何使用 Spring Framework 配置和開發 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)已更名為 Spring Data for Pivotal GemFire,以反映它現在是 Spring Data 專案的模組,並基於 Pivotal GemFire 構建。

3.1. 1.2 版本中的新增功能

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

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

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

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

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

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

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

  • 支援 Pivotal GemFire 7.0 中重新設計的 WAN 閘道器。

3.2. 1.3 版本中的新增功能

  • 已升級到 Spring Framework 3.2.8。

  • 已升級到 Spring Data Commons 1.7.1。

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

  • 在 SDG XML 名稱空間中添加了 <datasource> 元素,以簡化與 Pivotal GemFire 資料網格建立基本 客戶端連線

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

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

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

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

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

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

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

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

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

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

  • 支援區域中的 PDX 持久鍵。

  • 當使用 colocated-with 屬性指定並置時,支援在 Spring 上下文中正確建立分割槽區域 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。

  • 將 Spring Data for Pivotal GemFire 與 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]

  • Spring Data for Pivotal GemFire 現在可以在 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 容器中部署 Spring Data for Pivotal GemFire。

  • 刪除了 Spring Data for Pivotal GemFire XML 名稱空間區域型別元素中指定的所有預設值,以改為依賴 Pivotal GemFire 預設值。

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

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

  • 啟用了手動啟動 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 的屬性佔位符配置變數定位器和伺服器端點列表。

  • 支援將 <gfe-data:datasource> 元素與非 Spring 配置的 Pivotal GemFire 伺服器一起使用。

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

  • 基於註釋的資料過期

  • [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)。

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

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

  • GemFireCache.evict(key) 更改為在 SDG 的 Spring Cache Abstraction 支援中呼叫 Region.remove(key)

  • 修復了使用為 Pivotal GemFire 伺服器組配置的特定 Pool 關聯的客戶端 Region 上的儲存庫查詢的 RegionNotFoundException

  • 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 快取、快取伺服器、定位器、池、區域、索引、磁碟儲存、到期、驅逐、統計資訊、多播、HttpService、Auth、SSL、日誌記錄、系統屬性。

  • 添加了對類路徑上具有多個 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. 文件結構

以下章節介紹 Spring Data for Pivotal GemFire 提供的核心功能

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

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

  • 使用 Pivotal GemFire 序列化 介紹了對 Pivotal GemFire 對受管理物件的序列化和反序列化的增強。

  • POJO 對映 介紹了使用 Spring Data 將儲存在 Pivotal GemFire 中的 POJO 進行永續性對映。

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

  • 函式執行的註釋支援 介紹瞭如何建立和使用 Pivotal GemFire 函式,透過使用註釋在資料所在的位置執行分散式計算。

  • 連續查詢 (CQ) 介紹瞭如何使用 Pivotal GemFire 的連續查詢 (CQ) 功能來處理事件流,該事件流基於已定義並已在 Pivotal GemFire 的 OQL(物件查詢語言)中註冊的興趣。

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

  • 示例應用程式 介紹了隨發行版提供的示例,以說明 Spring Data for Pivotal GemFire 中提供的各種功能。

5. 使用 Spring 容器引導 Pivotal GemFire

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

本部分假定您基本熟悉 Pivotal GemFire。有關更多資訊,請參閱 Pivotal GemFire 產品文件

5.1. 在 Pivotal GemFire cache.xml 中使用 Spring 的優勢

Spring Data for Pivotal GemFire 的 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 名稱空間的背後,Spring Data for Pivotal GemFire 廣泛使用 Spring 的 FactoryBean 模式來簡化 Pivotal GemFire 元件的建立、配置和初始化。

Pivotal GemFire 提供了多個回撥介面,例如 CacheListenerCacheLoaderCacheWriter,這些介面允許開發人員新增自定義事件處理程式。使用 Spring 的 IoC 容器,您可以將這些回撥配置為普通 Spring Bean,並將它們注入到 Pivotal GemFire 元件中。這比本機 cache.xml 有了顯著的改進,後者提供的配置選項相對有限,並且要求回撥實現 Pivotal GemFire 的 Declarable 介面(請參閱 連線 Declarable 元件,瞭解如何在 Spring 容器中仍然使用 Declarables)。

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

5.2. 使用核心名稱空間

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

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

要使用 Spring Data for Pivotal GemFire 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 Spring Data for Pivotal GemFire XML 名稱空間字首。任何名稱都可以使用,但在本參考文件中,使用 gfe
2 XML 名稱空間字首對映到 URI。
3 XML 名稱空間 URI 位置。請注意,即使該位置指向外部地址(該地址確實存在且有效),Spring 也會在本地解析架構,因為它包含在 Spring Data for Pivotal GemFire 庫中。
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 元素以連線到現有的資料網格。此外,還支援配置池的所有屬性。此配置會自動為連線到定位器的群整合員上定義的每個區域建立客戶端區域 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)中開啟一個快取。在大多數情況下,快取只應建立一次。

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

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

<gfe:cache/>

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

所有依賴於 Cache 的 Pivotal GemFire 元件都遵循此命名約定,因此您無需顯式宣告 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 系統 屬性

例如,您可以使用在 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 成員能夠從定位器檢索常見的、基於叢集的共享配置。有關更多詳細資訊,請參閱 Pivotal GemFire 產品文件
5 使用 bean 引用的事務偵聽器回撥宣告示例。引用的 bean 必須實現 TransactionListener。可以實現 TransactionListener 來處理與事務相關的事件(例如 afterCommit 和 afterRollback)。
6 使用內部 bean 宣告的事務寫入器回撥宣告示例。bean 必須實現 TransactionWriterTransactionWriter 是可以否決事務的回撥。
7 使用 Bean 引用宣告 GatewayConflictResolver 回撥的示例。引用的 Bean 必須實現 https://gemfire-98-javadocs.docs.pivotal.io//org/apache/geode/cache/util/GatewayConflictResolver.html [GatewayConflictResolver]。GatewayConflictResolver 是一個 Cache 級別外掛,用於決定如何處理源自其他系統並透過 WAN 閘道器到達的事件。
8 啟用 Pivotal GemFire 的 DynamicRegionFactory,它提供分散式區域建立服務。
9 宣告 JNDI 繫結,以便在 Pivotal GemFire 事務中登記外部 DataSource。
啟用 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 時,應小心。

通常,只有在使用 Spring Data for Pivotal GemFire 的 XML 名稱空間來配置和引導新增到叢集的新非應用程式 Pivotal GemFire 伺服器時,才應啟用“自動重新連線”。換句話說,當使用 Spring Data for Pivotal GemFire 開發和構建碰巧也是 Pivotal GemFire 叢集的 peer 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()(如果應用程式甚至適用),這就是為什麼不建議對等 Cache 應用程式使用 Pivotal GemFire 的此“功能”。

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

使用基於群集的配置

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

Spring Data for Pivotal GemFire 的此功能(將 use-cluster-configuration 屬性設定為 true)的工作方式與 cache-xml-location 屬性相同,只是 Pivotal GemFire 配置元資料的來源透過定位器來自網路,而不是駐留在本地檔案系統中的本機 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),但不會記錄 Spring Data for Pivotal GemFire 的配置元資料。直接使用 Pivotal GemFire 的公共 Java API 時也是如此。它也不會被記錄。

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

5.4.2. 配置 Pivotal GemFire CacheServer

Spring Data for Pivotal GemFire 包含用於配置 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。一個 property placeholder 會讀取一個或多個屬性檔案,然後在執行時用值替換屬性佔位符。這樣做可以讓管理員更改值,而無需觸及主應用程式配置。Spring 還提供 SpEL 和一個 environment abstraction 來支援從主程式碼庫中將特定於環境的屬性外化,從而簡化跨多臺機器的部署。
為了避免初始化問題,Spring Data for Pivotal GemFire 啟動的 CacheServer 在 Spring 容器完全初始化之後啟動。這樣做可以讓宣告性定義的潛在區域、偵聽器、寫入器或例項化器在伺服器開始接受連線之前完全初始化並註冊。在以程式設計方式配置這些元素時請記住這一點,因為伺服器可能在元件之前啟動,因此客戶端無法立即看到它們。

5.4.3. 配置 Pivotal GemFire ClientCache

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

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

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

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

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

例如,要自定義 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 池和 Spring Data for Pivotal GemFire 池定義

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

<gfe:client-cache/>

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

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

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

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

<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,池被標識為 gemfirePool,客戶端區域被標識為“Example”。但是,ClientCachegemfirePool 初始化 Pivotal GemFire 的 DEFAULT 池,並且客戶端區域在客戶端和伺服器之間分發資料時使用 gemfirePool

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

<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 的池。Spring Data for Pivotal GemFire 導致 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

“Example”區域明確引用並專門使用 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 - 資料被分割槽到定義區域的群集中的許多快取成員之間的儲存桶(分片)中。這提供了較高的讀取和寫入效能,並且適用於對於單個節點而言過大的大型資料集。

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

  • 客戶端 - 從技術上講,客戶端區域是一個本地區域,充當一個代理,用於訪問群集中快取伺服器上託管的複製或分割槽區域。它可以儲存本地建立或獲取的資料。或者,它可以為空。本地更新會同步到快取伺服器。此外,客戶端區域可以訂閱事件,以便與訪問同一伺服器區域的遠端程序發起的更改保持最新(同步)。

有關各種區域型別及其功能以及配置選項的更多資訊,請參閱 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"/>)將特定區域引用為 Spring 容器中的 bean,或者您可以選擇透過使用以下方式匯入 cache.xml 中定義的所有區域

<gfe:auto-region-lookup/>

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

必須意識到 Spring Data for Pivotal GemFire 使用 Spring BeanPostProcessor 在建立並初始化快取之後對其進行後處理,以確定在 Pivotal GemFire 中定義的區域,並將其作為 bean 新增到 Spring ApplicationContext 中。

你可以注入這些“自動查詢”的區域,就像注入在 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"/>

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

5.5.3. 配置區域

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

  • LOCAL 區域:<local-region>

  • PARTITION 區域:<partitioned-region>

  • REPLICATE 區域:<replicated-region>

  • Client 區域:<client-region>

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

通用區域屬性

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

表 1. 通用區域屬性
名稱 說明

cache-ref

Pivotal GemFire Cache bean 引用

定義 Pivotal GemFire Cache 的 bean 的名稱(預設情況下為“gemfireCache”)。

cloning-enabled

布林值(預設值:false

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

close

布林值(預設值:false

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

concurrency-checks-enabled

布林值(預設值:true

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

data-policy

請參見 Pivotal GemFire 的 資料策略

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

銷燬

布林值(預設值:false

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

磁碟儲存引用

已配置磁碟儲存的名稱。

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

磁碟同步

布林值(預設值:true

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

ID

任何有效的 bean 名稱。

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

如果存在則忽略

布林值(預設值:false

如果區域已在快取中存在,則忽略此 bean 定義,從而導致查詢。

忽略 JTA

布林值(預設值:false

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

索引更新型別

同步非同步(預設:同步

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

初始容量

整數(預設:16)

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

鍵約束

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

預期的鍵型別。

負載因子

浮點數(預設:.75)

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

名稱

任何有效的區域名稱。

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

持久

*布林值(預設:false

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

快捷方式

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

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

統計資訊

布林值(預設值:false

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

模板

區域模板的名稱。

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

值約束

任何有效的完全限定 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>

以下示例使用 cache-listener 元素的備用形式,其中包含 ref 屬性。在定義單個 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 提供了一個回撥介面,以便在響應快取或 Region 事件時呼叫自定義程式碼。當您使用 Spring 的 IoC 容器時,該實現是一個標準的 Spring bean。為了簡化配置,該架構允許 cache-listener 元素出現一次,但是,如果允許出現多個例項,則它可以包含巢狀的 bean 引用和內部 bean 定義的任意組合。約定是使用單數形式(即 cache-listenercache-listeners),反映最常見的場景實際上是一個例項。我們已經在 高階快取 配置示例中看到了此模式的示例。

CacheLoaders 和 CacheWriters

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

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

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

<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 區域也可以進行壓縮,以減少 JVM 記憶體消耗和壓力,從而可能避免全域性 GC。為區域啟用壓縮後,儲存在區域記憶體中的所有值都將被壓縮,而鍵和索引將保持未壓縮狀態。將新值放入區域時會對其進行壓縮,並且從區域讀回所有值時會自動對其進行解壓縮。將值持久化到磁碟或透過網路傳送到其他對等成員或客戶端時,不會對其進行壓縮。

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

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

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

5.5.5. 堆外

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

使用堆外記憶體非常簡單,只需宣告要使用的記憶體量,然後啟用您的區域使用堆外記憶體,如下面的配置所示

<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)中。區域的完整路徑名也應在 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>

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

<gfe:client-region-template>

定義通用“Client”區域屬性。在 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 定義中定義的屬性和子元素會覆蓋父元素中的內容。

模板的工作原理

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

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

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

此行為已更改,現在預設行為是先建立區域。如果區域已存在,則建立邏輯將快速失敗,並丟擲適當的異常。但是,與 CREATE TABLE IF NOT EXISTS …​ DDL 語法非常相似,Pivotal GemFire 的 Spring Data <gfe:*-region> XML 名稱空間元素現在包含一個 ignore-if-exists 屬性,該屬性透過在嘗試建立區域之前先查詢按名稱標識的現有區域來恢復舊行為。如果按名稱找到現有區域,並且 ignore-if-exists 設定為 true,則在 Spring 配置中定義的區域 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;

    ...
}

在此,我們在應用程式 DAO 中注入對 Customers/Accounts 區域的引用。因此,開發人員在 Spring XML 配置元資料中為其中一些或所有這些區域定義 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 容器中分別作為 bean 引用為 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 中定義的區域 bean 包括以下內容:{ "Customers", "/Customers/Accounts", "/Customers/Accounts/Orders" }.這意味著前面示例中顯示的依賴注入引用(即 @Resource(name = "Customers/Accounts"))現在已損壞,因為實際上沒有定義名為 Customers/Accounts 的 bean。因此,您不應如前兩個示例中所示配置區域。

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

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

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

前面的示例中,巢狀的 replicated-region 元素用於引用子區域,顯示了前面提到的問題。客戶、帳戶和訂單區域和子區域是永續性的還是非永續性的?它們不是永續性的,因為這些區域在原生 Pivotal GemFire cache.xml 配置檔案中定義為 REPLICATE,並且在快取 bean 初始化之前存在(一旦處理了 <gfe:cache> 元素)。

5.5.8. 資料驅逐(帶溢位)

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

Spring Data for Pivotal GemFire 支援所有驅逐策略(條目計數、記憶體和堆使用),用於分割槽區域、複製區域以及客戶端、本地區域,方法是使用巢狀的 eviction 元素。

例如,要配置分割槽區域,使其在記憶體大小超過 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):物件在最後建立或更新後可在快取中保留的時間(以秒為單位)。對於條目,計數器在建立和放置操作中設定為零。區域計數器在建立區域時和條目重置其計數器時重置。

  • 空閒超時 (TTI):物件在最後一次訪問後可在快取中保留的時間(以秒為單位)。物件的空閒超時計數器在每次重置其 TTL 計數器時重置。此外,每次透過 get 操作或 netSearch 訪問條目時,條目的空閒超時計數器都會重置。每當某個條目的空閒超時重置時,區域的空閒超時計數器也會重置。

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

以下示例顯示了一個具有過期值的 PARTITION 區域

<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,您可以在各個區域條目值(或者換句話說,直接在應用程式域物件上)定義過期策略和設定。例如,您可以按照以下方式在基於會話的應用程式域物件上定義過期策略

@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 互不覆蓋。相反,當配置了不同的區域條目過期策略(例如 TTL 和 TTI)時,它們會相互補充。

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

<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 和 SDG 的 ExpirationActionType 的 'action'。這是為什麼呢?

嗯,輸入 Spring Data for Pivotal GemFire 的其他功能之一,利用 Spring 的核心基礎設施來方便配置:屬性佔位符和 Spring 表示式語言 (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` 必須與區域型別匹配,並且還必須與 `persistent` 屬性(如果也顯式設定)一致。如果將 `persistent` 屬性設定為 `false` 但指定了永續性 `DataPolicy`(例如 `PERSISTENT_REPLICATE` 或 `PERSISTENT_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 元素,用於建立本地區域。顧名思義,本地區域是獨立的,這意味著它們不與任何其他分散式系統成員共享資料。除此之外,所有常見的區域配置選項都適用。

以下示例顯示了一個最小的宣告(同樣,該示例依賴於 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 屬性
名稱 說明

copies

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-cache 元素為每種配置提供專門支援: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 使用定位器進行配置。定位器是一個單獨的程序,用於發現分散式系統中的快取伺服器和對等資料成員,建議用於生產系統。還可以使用 server 元素將 Pool 配置為直接連線到一個或多個快取伺服器。

有關在客戶端和 Pool 上設定的選項的完整列表,請參閱 Spring Data for Pivotal GemFire 架構(“Spring Data for Pivotal GemFire 架構”)和 Pivotal GemFire 關於 客戶端-伺服器配置 的文件。

客戶端興趣

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

以下示例顯示基於鍵和基於正則表示式的 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` 是以下列舉值:KEYSKEYS_VALUENONE。預設值為 KEYS_VALUESresult-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>

若要控制客戶端與叢集中的伺服器斷開連線後維護“durable”訂閱佇列的時間(以秒為單位),請在 <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(物件查詢語言)查詢的效能。

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

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

在 Pivotal GemFire 的 Spring Data XML 架構(也稱為 SDG XML 名稱空間)中,index bean 宣告不繫結到區域,這與 Pivotal GemFire 的本機 cache.xml 不同。相反,它們是頂級元素,類似於 <gfe:cache> 元素。這使您可以對任何區域宣告任意數量的索引,無論它們是剛建立的還是已經存在的——這比 Pivotal GemFire 的本機 cache.xml 格式有了顯著的改進。

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

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

考慮以下示例,其中有一個 lastName 屬性

@Region("Customers")
class Customer {

  @Id
  Long id;

  String lastName;
  String firstName;

  ...
}

現在考慮以下示例,其中有一個應用程式定義的 SDG 儲存庫用於查詢 Customer 物件

interface CustomerRepository extends GemfireRepository<Customer, Long> {

  Customer findByLastName(String lastName);

  ...
}

SDG 儲存庫查詢器/查詢方法導致生成並執行以下 OQL 語句

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

因此,您可能希望使用類似於以下語句建立 Index

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

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

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

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

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

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

5.6.1. 定義索引

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

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

define 設定為 true(其預設為 false)時,它不會在此時實際建立 Index。所有“已定義”索引都將在 Spring ApplicationContext “重新整理”時一次性建立,或者換句話說,當 Spring 容器釋出 ContextRefreshedEvent 時。Spring Data for Pivotal GemFire 將自己註冊為偵聽 ContextRefreshedEventApplicationListener。觸發時,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 異常。這些 Index 異常會被包裝在 SDG GemfireIndexException 中並重新丟擲。如果您希望 Spring Data for Pivotal GemFire 為您處理這些異常,則可以將這兩個 Index bean 定義選項中的任何一個設定為 true

IgnoreIfExists 始終優先於 Override,主要是因為它使用的資源更少,僅僅是因為它在這兩種異常情況下都會返回“現有”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 名稱。

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

當丟擲 IndexExistsExceptionoverride 設定為 true(或 <gfe:index override="true">)時,Index 將有效重新命名。請記住,當存在多個具有相同定義但名稱不同的索引時,將丟擲 IndexExistsExceptions

Spring Data for Pivotal GemFire 只能透過使用 Pivotal GemFire 的 API 來完成此操作,方法是先刪除現有的 Index,然後使用新名稱重新建立 Index。刪除或後續建立呼叫可能會失敗。無法以原子方式執行這兩個操作,如果任一操作失敗,則無法回滾此聯合操作。

但是,如果成功,則會遇到與 ignoreIfExists 選項之前相同的問題。任何使用查詢提示的現有 OQL 查詢語句,這些提示透過名稱引用舊 Index,都必須更改。

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

如果是這樣,SDG 很智慧,它會按原樣返回現有的 Index,即使在 override 上也是如此。此行為沒有害處,因為名稱和定義完全相同。當然,SDG 只能在能夠找到現有 Index 時才能完成此操作,這取決於 Pivotal GemFire 的 API。如果找不到,則不會發生任何事情,並且會丟擲包裝 IndexNameConflictException 的 SDG GemfireIndexException

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

IndexNameConflictExceptions 實際上是如何發生的?

丟擲 IndexExistsExceptions 可能並不少見,尤其是在使用多個配置源來配置 Pivotal GemFire(用於 Pivotal GemFire 的 Spring Data、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

用於 Pivotal GemFire 的 Spring Data 支援透過 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 定義多個檔案系統目錄,如前例所示。

請參閱 Pivotal GemFire 文件,以全面瞭解 永續性和溢位 以及 DiskStore 例項上的配置選項。

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:snapshot-service> 元素開始,該元素來自 <gfe-data> XML 名稱空間。

例如,您可以定義要載入和儲存的快取範圍快照,方法是使用幾個快照匯入和資料匯出定義,如下所示

<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 的 SnapshotServiceFactoryBean 會將 region-ref 屬性值解析為 Spring 容器中定義的區域 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 介面以及 Composite 軟體設計模式。

簡而言之,Composite 軟體設計模式使您可以組合多個相同型別的物件,並將聚合視為物件型別的單個例項——一個強大而有用的抽象。

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. 快照事件

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

為此,用於 Pivotal GemFire 的 Spring Data 定義了兩個其他 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 閘道器

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

5.10.1. Pivotal GemFire 7.0 中的 WAN 配置

在以下示例中,GatewaySenders 是透過向區域新增子元素(gateway-sendergateway-sender-ref)為 PARTITION 區域配置的。GatewaySender 可以註冊 EventFiltersTransportFilters

以下示例還顯示了 AsyncEventQueue 的示例配置,它還必須自動連線到區域(未顯示)

<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

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

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

您可以使用 ClientCache 例項將 Spring Boot 應用程式配置為 Pivotal GemFire 快取客戶端,該例項可以與用於管理應用程式資料的現有 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 上執行的 CacheServer 的“DEFAULT”Pool,該 CacheServer 偵聽埠 40404CacheServer 偵聽埠 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 強制執行的)。

您還可以配置其他 Pool 例項(除了使用 @ClientCacheApplication 註釋建立 ClientCache 例項時 Pivotal GemFire 提供的“DEFAULT”Pool 之外),方法是使用 @EnablePool@EnablePools 註釋。

@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 Cache 應用程式,您還可以建立 Pivotal GemFire Locator 應用程式。

Pivotal GemFire Locator 是一個 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 屬性。

此外,如果您在同一臺機器上派生多個定位器,則必須確保每個定位器在唯一埠上啟動。設定 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 定位器應用程式程序。此程序只能是定位器,不能是其他任何內容。如果您嘗試使用快取例項啟動定位器,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 提供的所有 Configurers 在回撥中獲取兩條資訊:由註解在 Spring 容器中建立的 Bean 的名稱,以及註解用於建立和配置 Pivotal GemFire 元件(例如,使用 ClientCacheFactoryBean 建立和配置 ClientCache 例項)的 FactoryBean 的引用。

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

鑑於 Configurer 可以像任何其他 POJO 一樣宣告為常規 Bean 定義,您可以組合不同的 Spring 配置選項,例如將 Spring 配置檔案與同時使用屬性佔位符和 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 是傳遞給回撥的 2 個引數之一。

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

以下示例顯示了這樣的安排

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. PropertiesProperties

按照通常的 Spring 方式,你甚至可以用其他 Properties 來表示 Properties,無論這是否是透過以下示例顯示在 application.properties 檔案中設定的巢狀屬性

Properties 的 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 註解在 Spring Pivotal GemFire CacheServer 應用程式中啟動嵌入式定位器,該應用程式在 localhost 上執行,偵聽預設定位器埠 10334。您可以使用相應的註解屬性自定義嵌入式定位器繫結的 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 類的執行配置檔案中只有一個應設定 -Dspring.profiles.active=embedded-locator Java 系統屬性。然後,您可以更改其他每個執行配置檔案的 ..name..cache.server.port,並在本地系統上執行一個小型叢集(分散式系統)的 Pivotal GemFire 伺服器。

@EnableLocator 註解僅作為開發時間註解,而不是應用程式開發人員在生產中使用的內容。我們強烈建議在叢集中將定位器作為獨立的程序執行。

有關 Pivotal GemFire 定位器工作原理的更多詳細資訊,請參閱 此處

6.7.2. 配置嵌入式管理器

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

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

您可能還希望將前面顯示的 Spring @CacheServerApplication 也啟用為管理器。為此,請使用 @EnableManager 為 Spring @Configuration@SpringBootApplication 類添加註釋。

預設情況下,管理器繫結到 localhost,偵聽預設管理器埠 1099。可以透過註釋屬性或相應屬性配置管理器的幾個方面。

以下示例顯示如何在 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

由於我們還啟用了嵌入式定位器,因此我們可以透過定位器間接連線到管理器。定位器允許 JMX 客戶端連線並在叢集中查詢管理器。如果不存在,定位器將承擔管理器的角色。但是,如果不存在定位器,我們需要使用以下內容直接連線到管理器

Gfsh connect 命令直接連線到管理器
gfsh>connect --jmx-manager=localhost[1099]
@EnableLocator 註釋類似,@EnableManager 註釋也僅用於開發時間,而不是應用程式開發人員在生產中使用的東西。我們強烈建議管理器(如定位器)成為叢集中獨立、獨立且專用的程序。

有關 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 伺服器,請向任何 @PeerCacheApplication@CacheServerApplication 註釋的類新增 @EnableHttpService 註釋,如下所示

執行嵌入式 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 服務,請向任何 @PeerCacheApplication@CacheServerApplication 註釋的類新增 @EnableMemcachedServer 註釋,如下所示

執行嵌入式 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 服務,請向任何 @PeerCacheApplication@CacheServerApplication 註釋的類新增 @EnableRedisServer 註釋,如下所示

執行嵌入式 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(視覺化統計資訊顯示) 工具來分析收集的統計資料。

要啟用統計資訊,請使用 @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 的 Spring ClientCache 應用程式,使用自定義複合 PdxSerializer
@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 系統屬性。

我們建議在將應用程式部署到生產環境時,在 gemfire.properties 檔案中設定這些 Pivotal GemFire 屬性。但是,在開發期間,可以根據需要單獨設定這些屬性,以用於原型製作、除錯和測試目的。

通常無需擔心的幾個不常用的 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 將快取中的資料組織到 區域 中。您可以將區域視為關係資料庫中的表。通常,區域應僅儲存一種型別的物件,這使其更適合構建有效的索引和編寫查詢。我們將在 後面 介紹索引。

以前,Pivotal GemFire 的 Spring Data 使用者需要透過編寫非常冗長的 Spring 配置元資料來顯式定義和宣告應用程式用來儲存資料的區域,無論使用 API 中 SDG 的 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 定義,除非您需要更精細的控制。

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

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

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

對 Book 進行建模的應用程式域物件型別
@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 的基本儲存庫,如下所示

Books 的儲存庫
interface BookRepository extends CrudRepository<Book, ISBN> { .. }

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

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

現在,當你定義 Book 類時,你還指定了 Book 例項對映(儲存)的區域,方法是在實體型別上宣告 Spring Data for Pivotal GemFire 對映註釋 @Region。當然,如果儲存庫介面(在本例中為 BookRepository)的型別引數中引用的實體型別(在本例中為 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 儲存庫時,從實體類建立區域最有用。Spring Data for Pivotal GemFire 的儲存庫支援透過 @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 註解),您還可以使用與 org.springframework.context.annotation.ComponentScan.Filter 註解完全相同的語義指定 includeexclude 過濾器。

有關更多詳細資訊,請參閱 @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 應用的預設值,引入了四個新的區域對映註解

  • @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 的 群集配置服務 會記住它。

例如,使用者可以在 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 的 群集配置服務,新增到伺服器群集以處理增加的負載(在後端)的任何其他對等成員也將具有相同的配置,例如

向群集新增其他對等成員
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”區域可能是實現書店應用程式服務所需的許多不同區域之一。SDG 允許從群集定義客戶端應用程式區域,如下所示,而不是必須單獨建立和配置每個區域

使用 @EnableClusterDefinedRegions 從群集定義客戶端區域
@ClientCacheApplication
@EnableClusterDefinedRegions
class BookStoreClientApplication {

    public static void main(String[] args) {
        ....
    }

    ...
}
@EnableClusterDefinedRegions 只能在客戶端上使用。
您可以使用 clientRegionShortcut 註解屬性來控制在客戶端上建立的區域型別。預設情況下,會建立一個客戶端 PROXY 區域。將 clientRegionShortcut 設定為 ClientRegionShortcut.CACHING_PROXY 以實現“近快取”。此設定適用於從群集定義區域建立的所有客戶端區域。如果您想控制從群集上定義的區域建立的客戶端區域的各個設定(如資料策略),那麼您可以使用 RegionConfigurer 根據區域名稱實現自定義邏輯。

然後,在您的應用程式中使用“Books”區域變得很簡單。您可以直接注入“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 和“Books”區域
interface BookRepository extends CrudRepository<Book, ISBN> {
    ...
}

然後,可以將自定義的BooksDataAccessObjectBookRepository注入到應用程式服務元件中,以執行所需的任何業務功能。

6.12.3. 配置驅逐

使用 Pivotal GemFire 管理資料是一項主動任務。通常需要進行調整,並且必須使用一系列功能(例如,驅逐和到期)才能有效地在記憶體中使用 Pivotal GemFire 管理資料。

鑑於 Pivotal GemFire 是記憶體資料網格 (IMDG),資料在記憶體中進行管理,並分發到參與叢集的其他節點,以最大程度地減少延遲、最大程度地提高吞吐量並確保資料的可用性。由於並非應用程式的所有資料通常都適合放在記憶體中(即使是在整個節點叢集中,更不用說單個節點上),因此可以透過向叢集中新增新節點來增加容量。這通常稱為線性橫向擴充套件(而不是縱向擴充套件,這意味著新增更多記憶體、更多 CPU、更多磁碟或更多網路頻寬——基本上是更多系統資源,以便處理負載)。

即便如此,即使在節點叢集中,通常也必須只將最重要的資料保留在記憶體中。記憶體耗盡,甚至接近滿負荷,幾乎從來都不是一件好事。Stop-the-world 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 提供以下到期註釋

  • 到期

  • 空閒超時到期

  • 生存時間到期

應用程式域物件型別可以註釋一個或多個到期註釋,如下所示

應用程式域物件特定到期策略
@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或不同的壓縮編解碼器來壓縮記憶體區域值。Pivotal GemFire 預設使用 Google 的Snappy壓縮庫。

要啟用壓縮,請使用 @EnableCompression 對應用程式類進行註釋,如下所示

啟用了區域壓縮的 Spring 應用程式
@SpringBootApplication
@ClientCacheApplication
@EnableCompression(compressorBeanName = "MyCompressor", regionNames = { "Customers", "Orders" })
class ClientApplication { .. }
compressorBeanNameregionNames 屬性均不是必需的。

compressorBeanName 預設為 SnappyCompressor,啟用 Pivotal GemFire 的 SnappyCompressor

regionNames 屬性是區域名稱的陣列,用於指定已啟用壓縮的區域。如果未明確設定 regionNames 屬性,則預設情況下所有區域均會壓縮值。

或者,您可以在 application.properties 檔案中使用 spring.data.gemfire.cache.compression.compressor-bean-namespring.data.gemfire.cache.compression.region-names 屬性來設定和配置這些 @EnableCompression 註釋屬性的值。
要使用 Pivotal GemFire 的區域壓縮功能,您必須在應用程式的 pom.xml 檔案(對於 Maven)或 build.gradle 檔案(對於 Gradle)中包含 org.iq80.snappy:snappy 依賴項。僅當您使用 Pivotal GemFire 預設支援區域壓縮時才需要這樣做,預設情況下該支援使用 SnappyCompressor。當然,如果您使用其他壓縮庫,則需要在應用程式的類路徑中包含該壓縮庫的依賴項。此外,您需要實現 Pivotal GemFire 的 Compressor 介面以調整您選擇的壓縮庫,將其定義為 Spring 壓縮器中的 bean,並將 compressorBeanName 設定為此自定義 bean 定義。

有關更多詳細資訊,請參閱 @EnableCompression 註釋 Javadoc

有關 Pivotal GemFire 壓縮的更多詳細資訊,請參閱 此處

6.12.6. 配置堆外記憶體

減輕 JVM 堆記憶體壓力和最大程度減少 GC 活動的另一種有效方法是使用 Pivotal GemFire 的堆外記憶體支援。

條目不會儲存在 JVM 堆中,而是儲存在系統的主記憶體中。堆外記憶體通常在以下情況下效果最佳:要儲存的物件大小一致,大多數小於 128K,並且不需要頻繁反序列化,如 Pivotal GemFire 使用者指南 中所述。

要啟用堆外記憶體,請使用 @EnableOffHeap 對應用程式類進行註釋,如下所示

啟用了堆外記憶體的 Spring 應用程式
@SpringBootApplication
@PeerCacheApplication
@EnableOffHeap(memorySize = 8192m regionNames = { "Customers", "Orders" })
class ServerApplication { .. }

memorySize 屬性是必需的。memorySize 屬性的值指定區域在兆位元組 (m) 或千兆位元組 (g) 中可以使用的主記憶體量。

regionNames 屬性是區域名稱的陣列,用於指定將條目儲存在主記憶體中的區域。如果未明確設定 regionNames 屬性,則預設情況下所有區域都使用主記憶體。

或者,您可以在 application.properties 檔案中使用 spring.data.gemfire.cache.off-heap.memory-sizespring.data.gemfire.cache.off-heap.region-names 屬性來設定和配置這些 @EnableOffHeap 註釋屬性的值。

有關更多詳細資訊,請參閱 @EnableOffHeap 註釋 Javadoc

6.12.7. 配置磁碟儲存

或者,您可以將區域配置為將資料持久化到磁碟。您還可以將區域配置為在區域條目被逐出時將資料溢位到磁碟。在這兩種情況下,都需要一個 DiskStore 來持久化和/或溢位資料。如果尚未為具有永續性或溢位的區域配置顯式 DiskStore,Pivotal GemFire 將使用 DEFAULT DiskStore

我們建議在將資料持久化和/或溢位到磁碟時定義特定於區域的 DiskStores

Spring Data for Pivotal GemFire 提供了註釋支援,用於透過使用 @EnableDiskStore@EnableDiskStores 註釋對應用程式類進行註釋來定義和建立應用程式區域 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 註解(由 @EnableDiskStores 註解本身組成)建立的 DiskStores 的通用 DiskStore 屬性。各個 DiskStore 配置會覆蓋特定全域性設定,但 @EnableDiskStores 註解方便地定義了適用於由該註解聚合的所有 DiskStores 的通用配置屬性。

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 區域永續性和溢位(使用 DiskStores)的更多詳細資訊。

6.12.8. 配置索引

除非可以訪問資料,否則在區域中儲存資料並沒有多大用處。

除了 Region.get(key) 操作(尤其是在預先知道鍵的情況下),通常透過對包含資料的區域執行查詢來檢索資料。使用 Pivotal GemFire 時,查詢是使用物件查詢語言 (OQL) 編寫的,客戶端希望訪問的特定資料集在查詢的謂詞中表示(例如,SELECT * FROM /Books b WHERE b.author.name = 'Jon Doe')。

通常,沒有索引的查詢效率低下。在沒有索引的情況下執行查詢時,Pivotal GemFire 會執行相當於全表掃描的操作。

為查詢謂詞中用於匹配感興趣資料的物件上的欄位建立並維護索引,如查詢的投影所表達的那樣。可以建立不同型別的索引,例如 雜湊 索引。

Spring Data for Pivotal GemFire 使得在儲存和訪問資料的區域上建立索引變得很容易。我們可以在 Java 中建立 Index bean 定義,如下所示,而不是像以前那樣使用 Spring 配置顯式宣告 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 實體類,我們可以註釋 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 註釋的欄位或屬性在儲存條目時用作區域中的鍵。

  • @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 註釋不起作用。從本質上講,索引是從實體類型別上的欄位或屬性定義的,必須掃描實體類以檢查實體的欄位和屬性是否存在索引註釋。如果沒有此掃描,將找不到索引註釋。我們還強烈建議您限制掃描範圍。

雖然 Pivotal GemFire 儲存庫中的 Spring Data 還不(尚未)支援 Lucene 查詢,但 SDG 透過使用熟悉的 Spring 模板設計模式為 Pivotal GemFire Lucene 查詢提供了全面的支援

最後,我們用幾個使用索引時需要記住的額外提示來結束本節

  • 雖然執行 OQL 查詢不需要 OQL 索引,但執行基於 Lucene 文字的搜尋需要 Lucene 索引。

  • OQL 索引不會持久化到磁碟。它們僅保留在記憶體中。因此,當 Pivotal GemFire 節點重新啟動時,必須重建索引。

  • 您還需要了解維護索引相關的開銷,特別是由於索引僅儲存在記憶體中,尤其是在更新區域條目時。索引“維護”可以配置為非同步任務。

在重新啟動必須重建索引的 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 的函式註釋 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 區域。在呼叫任何快取註釋的應用程式服務方法之前,該區域必須存在。這適用於 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 註釋(如“配置區域”中所述的 @EnableEntityDefinedRegions 註釋)會檢查整個 Spring 應用程式,快取帶註釋的服務元件,以識別應用程式在執行時所需的所有快取,並在應用程式啟動時為這些快取建立 Pivotal GemFire 中的區域。

建立的區域是建立區域的應用程式程序的本地區域。如果應用程式是 peer Cache,則區域僅存在於應用程式節點上。如果應用程式是 ClientCache,則 SDG 會建立客戶端 PROXY 區域,並期望群集中的伺服器上已存在具有相同名稱的區域。

SDG 無法使用 Spring CacheResolver 確定服務方法所需的快取,以解析操作在執行時使用的快取。
SDG 還支援應用程式服務元件上的 JCache (JSR-107) 快取註釋。有關可用於替代 JCache 快取註釋的等效 Spring 快取註釋,請參閱核心 Spring Framework Reference Guide

有關在 Spring 的快取抽象中使用 Pivotal GemFire 作為快取提供程式的更多詳細資訊,請參閱 “對 Spring 快取抽象的支援” 部分。

有關 Spring 快取抽象的更多詳細資訊,請參閱 此處

6.15. 配置群集配置推送

這可能是 Spring Data for Pivotal GemFire 中最激動人心的新功能。

當客戶端應用程式類用 @EnableClusterConfiguration 註釋時,客戶端應用程式在 Spring 容器中定義並宣告為 bean 的任何區域或索引都會“推送”到客戶端連線到的伺服器群集。不僅如此,而且此“推送”以一種方式執行,即 Pivotal GemFire 在使用 HTTP 時會記住客戶端推送的配置。如果群集中的所有節點都宕機,它們會以與之前相同的配置重新啟動。如果向群集新增新伺服器,它將獲取相同的配置。

從某種意義上來說,此功能與使用 Gfsh 手動在叢集中的所有伺服器上建立區域和索引並無太大區別。但現在,有了 Spring Data for Pivotal GemFire,您不再需要使用 Gfsh 來建立區域和索引。您的 Spring Boot 應用程式在 Spring Data for Pivotal GemFire 的支援下,已包含建立區域和索引所需的所有配置元資料。

當您使用 Spring Data Repository 抽象時,我們瞭解您的應用程式所需的所有區域(例如由 @Region 註釋的實體類定義的區域)和索引(例如由 @Indexed 註釋的實體欄位和屬性定義的索引)。

當您使用 Spring 的快取抽象時,我們還了解應用程式的服務元件所需的快取註釋中標識的所有快取的所有區域。

從本質上講,您只需使用 Spring 框架開發應用程式,並使用其所有 API 和功能(無論以註釋元資料、Java、XML 或其他方式表示,無論用於配置、對映或其他目的),即可告訴我們所有我們需要了解的資訊。

關鍵在於,您可以專注於應用程式的業務邏輯,同時使用框架的功能和支援基礎設施(例如 Spring 的快取抽象、Spring Data 儲存庫、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 會小心不要破壞伺服器中已定義的任何現有區域和索引。這尤其重要,例如,當區域已包含資料時!

目前,沒有選項可以覆蓋任何現有區域或索引定義。要重新建立區域或索引,您必須使用 Gfsh 首先銷燬區域或索引,然後重新啟動客戶端應用程式,以便將配置再次推送到伺服器。或者,您可以使用 Gfsh 手動(重新)定義區域和索引。
Gfsh 不同,Spring Data for Pivotal GemFire 僅支援從客戶端在伺服器上建立區域和索引。對於高階配置和用例,您應使用 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 資料儲存庫、Spring 的快取抽象(其中區域和索引不僅在客戶端建立,還推送到叢集中的伺服器)。

從那裡,您只需要執行以下操作

  • 定義使用對映和索引註釋進行註釋的應用程式的域模型物件。

  • 定義儲存庫介面以支援基本資料訪問操作和對每個實體型別的簡單查詢。

  • 定義包含處理實體的業務邏輯的服務元件。

  • 在需要快取、事務行為等的服務方法上宣告適當的註釋。

在這種情況下,沒有任何內容與應用程式後端服務(例如 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 配置屬性或特性:金鑰庫、使用者名稱/密碼等。

您可以使用 SSL 單獨配置不同的 Pivotal GemFire 元件(GATEWAYHTTPJMXLOCATORSERVER),或者使用 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 應用程式類進行註釋,並定義一個或多個 Apache Shiro Realms 作為 Spring 容器中的 bean,以訪問應用程式的安全元資料(即授權使用者、角色和許可權)。

第一種方法的問題在於你必須實現自己的 SecurityManager,這可能相當繁瑣且容易出錯。實現自定義 SecurityManager 在從儲存元資料的任何資料來源(如 LDAP 甚至專有內部資料來源)訪問安全元資料方面提供了一些靈活性。但是,透過配置和使用 Apache Shiro Realms 已經解決了該問題,而 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 的 關於 Realms 的文件,瞭解詳細資訊。

當 Apache Shiro 位於叢集中伺服器的 CLASSPATH 中,並且一個或多個 Apache Shiro Realms 已被定義為 Spring 容器中的 bean 時,Spring Data for Pivotal GemFire 會檢測到此配置,並在使用 @EnableSecurity 註釋時使用 Apache Shiro 作為安全提供程式來保護你的 Pivotal GemFire 伺服器。

你可以在此 spring.io 部落格文章 中找到有關 Spring Data for Pivotal GemFire 使用 Apache Shiro 支援 Pivotal GemFire 的新整合安全框架的更多資訊。

請參閱 @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
預設情況下,當 Spring Boot 的 application.properties 檔案位於應用程式 CLASSPATH 的根目錄中時,Spring Boot 可以找到它。當然,Spring 支援多種使用其 資源抽象 來查詢資源的方法。

請參閱 @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 或群集配置)中定義的區域,並將這些區域自動註冊為 Spring 容器中的 bean。此註釋對應於 SDG XML 名稱空間中的 <gfe:auto-region-lookup> 元素。更多詳細資訊可以在此找到。在使用 Spring 和 Spring Data for Pivotal GemFire 時,使用者通常應該更喜歡 Spring 配置。請參閱“配置區域”和“配置群集配置推送”。

  • @EnableBeanFactoryLocator:啟用 SDG GemfireBeanFactoryLocator 功能,該功能僅在使用外部配置元資料(例如 cache.xml)時才有用。例如,如果您在 cache.xml 中定義的區域上定義了 CacheLoader,則仍然可以使用 Spring 配置中定義的關係資料庫 DataSource bean 自動裝配此 CacheLoader。此註釋利用了此 SDG 功能,如果您有大量舊配置元資料(例如 cache.xml 檔案),則可能很有用。

  • @EnableGemFireAsLastResource:在全域性 - JTA 事務管理中與 Pivotal GemFire 一起討論。

  • @EnableMcast:啟用 Pivotal GemFire 的舊對等發現機制,該機制使用基於 UDP 的多播網路。(已棄用。請改用 Pivotal GemFire 定位器。請參閱“配置嵌入式定位器”。

  • @EnableRegionDataAccessTracing:用於除錯目的。此註釋透過註冊一個 AOP 方面來啟用對區域執行的所有資料訪問操作的跟蹤,該方面代理在 Spring 容器中宣告為 bean 的所有區域,攔截區域操作並記錄事件。

6.19. 結論

正如我們在前幾部分中瞭解到的,Spring Data for Pivotal GemFire 的基於註釋的新配置模型提供了巨大的能力。希望它能達到其目標,讓您在將 Pivotal GemFire 與 Spring 一起使用時快速輕鬆地入門。

請記住,當您使用新註釋時,您仍然可以使用 Java 配置或 XML 配置。您甚至可以透過在 Spring 的 @Configuration@SpringBootApplication 類中使用 Spring 的 @Import@ImportResource 註釋來組合所有這三種方法。當您明確提供一個 bean 定義時,該定義原本應由 Spring Data for Pivotal GemFire 使用其中一個註釋提供,基於註釋的配置就會退出。

在某些情況下,您甚至可能需要退回到 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,只需用 @CacheServerApplication 註釋替換 @PeerCacheApplication 註釋。這將在“localhost”上啟動一個 CacheServer,偵聽預設 CacheServer40404

請參閱 使用 Spring 配置 Pivotal GemFire 應用程式 以獲取更多詳細資訊。

6.20.3. 配置嵌入式定位器

使用 @EnableLocator 註釋您的 Spring @PeerCacheApplication@CacheServerApplication 類,以啟動一個嵌入式定位器,該定位器繫結到偵聽預設定位器埠 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 類,以啟動一個嵌入式管理器,該管理器繫結到偵聽預設管理器埠 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 介面或宣告 1 個或多個 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. 配置快取

要在 Spring 的 快取抽象 中將 Pivotal GemFire 用作快取提供程式,並讓 SDG 為應用程式服務元件所需的快取自動建立 Pivotal GemFire 區域,請使用 @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 是可選的。也就是說,如果您願意,可以手動定義您的區域。

請參閱 配置 Spring 的快取抽象 瞭解更多詳情。

6.20.15. 為持久化應用程式配置區域、索引、儲存庫和實體

為了簡化建立 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 對映註釋指定將儲存實體的區域。使用 @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;

}
@EnableEntityDefinedRegions 使用 @Region("Books") 實體類註釋來確定應用程式所需的區域。請參閱 配置特定於型別的區域POJO 對映 瞭解更多詳情。

最後,使用簡單查詢定義 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

請參閱 配置區域 瞭解更多詳情。

請參閱 Spring Data for Pivotal GemFire 儲存庫 瞭解更多詳情。

6.20.16. 從叢集定義的區域配置客戶端區域

或者,您可以使用 @EnableClusterDefinedRegions 從已在叢集中定義的區域定義客戶端 [*PROXY] 區域,如下所示

@SpringBootApplication
@ClientCacheApplication
@EnableClusterDefinedRegions
@EnableGemfireRepositories
public class ClientApplication {

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

  ...
}

請參閱 配置的叢集定義區域 瞭解更多詳情。

6.20.17. 配置函式

Pivotal GemFire 函式在分散式計算場景中非常有用,在該場景中,需要資料的潛在昂貴計算可以在群集中的節點上並行執行。在這種情況下,將邏輯帶到資料所在(儲存)的位置比請求和獲取資料以供計算處理更有效率。

使用 @EnableGemfireFunctions@GemfireFunction 註釋來啟用 Pivotal GemFire 函式定義,這些定義實現為 POJO 上的方法,如下所示

@PeerCacheApplication
@EnableGemfireFunctions
class ServerApplication {

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

  @GemfireFunction
  Integer computeLoyaltyPoints(Customer customer) {
    ...
  }
}

使用 @EnableGemfireFunctionExecutions 和 1 個函式呼叫註釋:@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 應用程式時,只需推送使用 Pivotal GemFire 開發時已表達的配置元資料即可。

這與使用 @EnableClusterConfiguration(..) 註釋主應用程式類一樣簡單。

使用 @EnableClusterConfiguration
@ClientCacheApplication
@EnableClusterConfiguration(useHttp = true)
class ClientApplication {
  ...
}
大多數情況下,在使用客戶端/伺服器拓撲時,尤其是在生產環境中,叢集的伺服器將使用 Gfsh 啟動。在這種情況下,通常使用 HTTP(S) 將配置元資料(例如 Region 和索引定義)傳送到叢集。使用 HTTP 時,配置元資料將被髮送到叢集中的 Manager,並在叢集中的伺服器節點中一致地進行分佈。
為了使用 @EnableClusterConfiguration,必須在 Spring 應用程式類路徑中宣告 org.springframework:spring-web 依賴項。

參見 配置叢集配置推送 瞭解更多詳情。

6.20.20. 配置 GatewayReceivers

不同 Pivotal GemFire 叢集之間的資料複製是一種日益重要的容錯和高可用性 (HA) 機制。Pivotal GemFire WAN 複製是一種允許一個 Pivotal GemFire 叢集以可靠且容錯的方式將其資料複製到另一個 Pivotal GemFire 叢集的機制。

Pivotal GemFire WAN 複製需要配置兩個元件

  • GatewayReceiver - WAN 複製元件,用於從遠端 Pivotal GemFire 叢集的 GatewaySender 接收資料。

  • GatewaySender - WAN 複製元件,用於向遠端 Pivotal GemFire 叢集的 GatewayReceiver 傳送資料。

要啟用 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 節點上進行配置。

在上述示例中,應用程式配置了 2 個區域,Region1Region2。此外,將配置兩個 GatewaySenders 來為這兩個區域提供服務。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 快取和區域後,可以在應用程式物件中注入和使用它們。本章介紹了與 Spring 的事務管理功能和 DAO 異常層次結構的整合。本章還涵蓋了對 Pivotal GemFire 託管物件的依賴注入的支援。

7.1. GemfireTemplate

與 Spring 提供的許多其他高階抽象一樣,Spring Data for Pivotal GemFire 提供了一個 模板 來簡化 Pivotal GemFire 資料訪問操作。該類提供了包含常見區域操作的多個方法,但也提供了使用 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 方法相比,這些方法可以在多個區域中執行查詢、執行投影等。

當查詢透過 SelectResults 選擇多項時,應使用 find 方法,而後者 findUnique,顧名思義,僅在返回一個物件時使用。

7.2. 異常轉換

使用新的資料訪問技術不僅需要適應新的 API,而且還需要處理特定於該技術異常。

為了適應異常處理案例,Spring Framework 提供了與技術無關且一致的 異常層次結構,它將應用程式從專有異常(通常是“已檢查”的異常)抽象為一組重點執行時異常。

Spring Framework 文件中所述,異常轉換可以透過使用 @Repository 註釋和 AOP 透過定義 PersistenceExceptionTranslationPostProcessor bean,透明地應用於你的資料訪問物件 (DAO)。只要聲明瞭 CacheFactoryBean,在使用 Pivotal GemFire 時也會啟用相同的異常轉換功能,例如使用 <gfe:cache/><gfe:client-cache> 宣告,它充當異常轉換器,並由 Spring 基礎結構自動檢測並相應使用。

7.3. 本地、快取事務管理

Spring Framework 最流行的功能之一是 事務管理

如果你不熟悉 Spring 的事務抽象,那麼我們強烈建議 閱讀有關 Spring 的事務管理 基礎結構,因為它提供了一致的 程式設計模型,可以在多個 API 中透明地工作,並且可以透過程式設計方式或宣告方式(最流行的選擇)進行配置。

對於 Pivotal GemFire,Spring Data for Pivotal GemFire 提供了一個專門的、按快取劃分的 PlatformTransactionManager,一旦宣告,便允許透過 Spring 以原子方式執行區域操作

使用 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 的事務中維護對“最後一個資源”的非 XA 相容資源的支援,儘管 JTA 規範中實際上並不需要這樣做。有關非 XA 相容“最後一個資源”的含義的更多資訊,請參閱 Red Hat 的文件。事實上,Red Hat 的 JBoss 專案 Narayana 就是這樣一個 LGPL 開源實現。Narayana 將其稱為“最後一個資源提交最佳化”(LRCO)。更多詳細資訊請參見此處

但是,無論您是在具有支援“最後一個資源”的開源 JTA 事務管理實現的獨立環境中使用 Pivotal GemFire,還是在受管環境(例如 Java EE AS,如 WAS)中使用,Spring Data for Pivotal GemFire 都能滿足您的需求。

要正確地將 Pivotal GemFire 用作涉及多個事務性資源的 JTA 事務中的“最後資源”,您必須完成一系列步驟。此外,此類安排中只能有一個非 XA 相容資源(例如 Pivotal GemFire)。

1) 首先,您必須在 Pivotal GemFire 文件中完成步驟 1-4,此處

上述第 1 步獨立於您的 Spring [Boot] 和/或 [Data for Pivotal GemFire] 應用程式,並且必須成功完成。

2) 參考 Pivotal GemFire 文件中的步驟 5,Spring Data for Pivotal GemFire 的註釋支援將嘗試在使用 @EnableGemFireAsLastResource 註釋時為您設定 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;
}

對等 Cache XML

使用 XML 設定 copy-on-read(伺服器)
<gfe:cache ... copy-on-read="true"/>

對等 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 註釋匯入包含 2 個 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() 時),Spring 基於 JTA 的 PlatformTransactionManager 會適當地為您處理上述步驟 1 和 4。

步驟 2 和 3 由 Spring Data for Pivotal GemFire 的新 Aspect 處理,這些 Aspect 透過 @EnableGemFireAsLastResource 註釋啟用。

當然,步驟 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 配置為“最後資源”的更多詳細資訊,請參閱此處

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 簡化了 CQ 事件的建立、註冊、生命週期和分派,透過使用 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 依賴項。它確實是我們能夠並且可以透過以下配置將其變成 EDP 的 POJO。

該類不必實現介面;僅使用介面來更好地展示契約和實現之間的解耦。
<?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介面列出了允許的型別。

上面的示例使用 Pivotal GemFire 的 Spring Data 名稱空間來宣告事件偵聽器容器並自動註冊偵聽器。完整的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例項將任意引數傳遞給宣告的類。

在本節中,我們將介紹在使用 Spring 在cache.xml中定義這些可插入元件時如何配置這些元件,同時將 Cache/Region 配置保留在cache.xml中。這允許您的可插入元件專注於應用程式邏輯,而不是DataSources或其他協作者的位置或建立。

但是,如果您正在啟動一個全新專案,建議您直接在 Spring 中配置 Cache、Region 和其他可插入 Pivotal GemFire 元件。這避免了繼承本節中介紹的Declarable介面或基類。

有關此方法的更多資訊,請參閱以下邊欄。

消除Declarable元件

開發人員可以透過 Spring 完全配置自定義型別,如 配置區域 中所述。這樣,開發人員不必實現 Declarable 介面,還可以從 Spring IoC 容器的所有特性中受益(不僅僅是依賴注入,還有生命週期和例項管理)。

作為使用 Spring 配置 Declarable 元件的示例,請考慮以下宣告(取自 Declarable Javadoc

<cache-loader>
   <class-name>com.company.app.DBLoader</class-name>
   <parameter name="URL">
     <string>jdbc://12.34.56.78/mydb</string>
   </parameter>
</cache-loader>

為了簡化解析、轉換引數和初始化物件的任務,Pivotal GemFire 的 Spring Data 提供了一個基類 (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自動裝配宣告例項。這意味著,除非該例項提供了任何依賴注入元資料,否則容器將查詢物件設定器並嘗試自動滿足這些依賴關係。但是,開發人員還可以使用 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”),則 CacheManager Bean 定義上的 cache-ref 屬性不是必需的,即 <gfe:cache> 沒有顯式 ID。

當宣告 GemfireCacheManager(單例)bean 例項並啟用宣告式快取(在 XML 中使用 <cache:annotation-driven/> 或在 JavaConfig 中使用 Spring 的 @EnableCaching 註解),Spring 快取註解(例如 @Cacheable)會標識將使用 Pivotal GemFire 區域將資料快取到記憶體中的“快取”。

這些快取(即區域)必須在使用它們的快取註解之前存在,否則會發生錯誤。

例如,假設您有一個客戶服務應用程式,其中 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 簡化和改進 Java 中 Pivotal GemFire 自定義序列化的各種方式。

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 允許自動生成 Instantiator 類,該類在不使用反射的情況下例項化新型別(使用預設建構函式)。以下示例演示如何建立例項化器

<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 物件對映、物件建立、欄位和屬性訪問、可變性和不可變性的基礎知識。請注意,本節僅適用於不使用底層資料儲存的物件對映的 Spring Data 模組(如 JPA)。此外,請務必查閱特定於儲存的部分以瞭解特定於儲存的物件對映,如索引、自定義列或欄位名稱等。

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 持有底層物件的 mutable 例項。這是為了啟用對其他不可變屬性的修改。
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%。

  • 提供一個 all-args 建構函式 — 即使你不能或不想將你的實體建模為不可變值,提供一個將實體的所有屬性(包括可變屬性)作為引數的建構函式仍然有價值,因為這允許物件對映跳過屬性填充以獲得最佳效能。

  • 使用工廠方法而不是過載建構函式來避免 @PersistenceConstructor — 由於需要一個 all-argument 建構函式來獲得最佳效能,我們通常希望公開更多應用程式用例特定的建構函式,這些建構函式省略自動生成識別符號等內容。這是一個既定的模式,即使用靜態工廠方法來公開 all-args 建構函式的這些變體。

  • 確保你遵守允許使用生成的例項化器和屬性訪問器類的約束 — 

  • 對於要生成的識別符號,仍然使用 final 欄位與 wither 方法結合使用 — 

  • 使用 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 提供了將儲存在區域中的實體對映的支援。對映元資料透過對應用程式域類使用註釋來定義,如下例所示

示例 3. 將域類對映到 Pivotal GemFire 區域
@Region("People")
public class Person {

  @Id Long id;

  String firstname;
  String lastname;

  @PersistenceConstructor
  public Person(String firstname, String lastname) {
    // …
  }

  …
}

@Region 註釋可用於定製儲存 Person 類的例項的區域。@Id 註釋可用於註釋應作為快取區域鍵使用的屬性,標識區域條目。@PersistenceConstructor 註釋有助於消除歧義,即多個可能可用的建構函式,獲取引數並顯式標記註釋為建構函式的建構函式作為用於構造實體的建構函式。在沒有或僅具有單個建構函式的應用程式域類中,可以省略註釋。

除了將實體儲存在頂級區域中之外,還可以將實體儲存在子區域中,如下例所示

@Region("/Users/Admin")
public class Admin extends User {
  …
}

@Region("/Users/Guest")
public class Guest extends User {
  …
}

請務必使用 Pivotal GemFire 區域的完整路徑,如 Spring Data for Pivotal GemFire XML 名稱空間透過使用 <*-region> 元素的 idname 屬性定義的那樣。

9.2.1. 按區域型別進行實體對映

除了 @Region 註釋之外,Spring Data for Pivotal GemFire 還識別特定於型別的區域對映註釋:@ClientRegion@LocalRegion@PartitionRegion@ReplicateRegion

在功能上,這些註釋在 SDG 對映基礎架構中與通用 @Region 註釋的處理方式完全相同。但是,這些附加對映註釋在 Spring Data for Pivotal GemFire 的註釋配置模型中非常有用。當與 Spring @Configuration 註釋類上的 @EnableEntityDefinedRegions 配置註釋結合使用時,可以在本地快取中生成區域,無論應用程式是客戶端還是對等方。

這些註釋讓你可以更具體地指定應用程式實體類應對映到的區域型別,並且還對區域的資料管理策略產生影響(例如,分割槽(也稱為分片)與複製資料)。

將這些特定於型別的區域對映註釋與 SDG 註釋配置模型一起使用,可以讓你不必在配置中顯式定義這些區域。

9.3. 儲存庫對映

作為在實體類上使用 @Region 註釋來指定實體儲存在其中的區域的替代方法,你還可以對實體的 Repository 介面指定 @Region 註釋。有關更多詳細資訊,請參閱 Spring Data for Pivotal GemFire 儲存庫

但是,假設你想要將 Person 記錄儲存在多個 Pivotal GemFire 區域中(例如,PeopleCustomers)。然後,你可以按如下方式定義相應的 Repository 介面擴充套件

@Region("People")
public interface PersonRepository extends GemfireRepository<Person, String> {
…
}

@Region("Customers")
public interface CustomerRepository extends GemfireRepository<Person, String> {
...
}

然後,單獨使用每個儲存庫,你可以將實體儲存在多個 Pivotal GemFire 區域中,如下面的示例所示

@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 的建構函式。

為了為建構函式引數提供引數,序列化程式使用 Spring 的 @Value 註釋從提供的 PdxReader 讀取具有命名建構函式引數的欄位,顯式地標識,如下面的示例所示

示例 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 屬性。

  • 自動處理只讀屬性。

  • 自動處理瞬態屬性。

  • 允許以 null 和型別安全的方式進行更健壯的型別過濾(例如,不限於僅使用正則表示式表示型別)。

我們現在更詳細地探討 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 註釋的欄位或屬性也指定為實體的識別符號。

例如

class Customer {

  @Id
  Long id;

  ...
}

在這種情況下,Customer id 欄位在 PDX 型別元資料中標記為識別符號欄位,方法是在序列化期間呼叫 PdxSerializer.toData(..) 方法時使用 PdxWriter.markIdentifierField(:String)

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 欄位混淆)被視為只讀。

因此,在反序列化期間,MappingPdxSerializer 不會嘗試在 PdxSerializer.fromData(:Class<ApplicationDomainType>, :PdxReader) 方法中填充 ApplicationDomainType 例項時為此屬性設定值,特別是如果 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() {
    ...
  }

  ...
}

Process id 欄位和可讀 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.*

此外,在呼叫 PdxSerializer.toData(:Object, :PdxWriter)PdxSerializer.fromData(:Class<?>, :PdxReader) 方法時,MappingPdxSerializer 會篩選 null 物件和 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. Pivotal GemFire 儲存庫的 Spring 資料

Spring Data for Pivotal GemFire 提供對使用 Spring Data Repository 抽象的支援,以便輕鬆將實體持久化到 Pivotal GemFire,並執行查詢。此處提供了 Repository 程式設計模型的一般介紹 here

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>

前面的配置片段查詢配置基本包下的介面,併為這些介面建立 Repository 例項,這些例項由 SimpleGemFireRepository 支援。

除非將應用程式域類正確對映到已配置的區域,否則引導過程將失敗。

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 的位置之外,它沒有其他用途。

除了 basePackages 和 basePackageClasses 屬性之外,與 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 不支援“分散式”聯接。此外,Equi-Join OQL 查詢必須在 Pivotal GemFire 函式內執行。有關 Pivotal GemFire Equi-Join 查詢 的更多詳細資訊,請參閱此處

SDG 的儲存庫基礎設施擴充套件的許多其他方面也可以自定義。有關所有配置設定的更多詳細資訊,請參閱@EnableGemfireRepositories Javadoc。

10.3. 執行 OQL 查詢

Spring Data for Pivotal GemFire 儲存庫支援定義查詢方法,以便針對受管理實體對映到的區域輕鬆執行 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<String> x)

x.firstname IN SET $1

NotIn

findByFirstnameNotIn(Collection<String> 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

IsTrueTrue

findByActiveIsTrue()

x.active = true

IsFalseFalse

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 儲存庫實現(例如 Spring Data JPA 或 Spring Data Redis)忽略,這些實現沒有類似的查詢語言特性。

例如,許多資料儲存很可能沒有實現 Pivotal GemFire 的 OQL IMPORT 關鍵字。將 IMPORT 實現為註釋(即 @Import),而不是作為查詢方法簽名(具體來說,方法“名稱”)的一部分,在評估查詢方法名稱以構建另一個適合資料儲存語言的查詢時不會干擾解析基礎架構。

目前,Spring Data for Pivotal GemFire 支援的 Pivotal GemFire OQL 查詢語言擴充套件集包括

表 5. 儲存庫查詢方法支援的 Pivotal GemFire OQL 擴充套件
關鍵字 註釋 說明 引數

提示

@Hint

OQL 查詢索引提示

String[](例如 @Hint({ "IdIdx", "TxDateIdx" }))

匯入

@Import

限定特定於應用程式的型別。

String(例如 @Import("org.example.app.domain.Type"))

限制

@Limit

限制返回的查詢結果集。

Integer(例如 @Limit(10); 預設值為 Integer.MAX_VALUE)

TRACE

@Trace

啟用特定於 OQL 查詢的除錯。

不適用

例如,假設您有一個 `Customers` 應用程式域類和相應的 Pivotal GemFire 區域以及一個 `CustomerRepository` 和一個查詢方法,用於按姓氏查詢 `Customers`,如下所示

示例 10.示例 Customers 儲存庫
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 的儲存庫擴充套件在將 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 儲存庫抽象,因此用於定義特定於資料儲存的查詢(例如 OQL)的查詢方法約定既簡單又方便。但是,有時仍然需要檢查甚至可能修改從儲存庫查詢方法生成的查詢。

自 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);

}

提供其他預設方法,讓你可以類似於 java.util.function.Function.andThen(:Function)java.util.function.Function.compose(:Function) 的工作方式來組合 QueryPostProcessor 例項。

此外,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 介面方法生成的查詢。

例如,你可能希望記錄來自所有應用程式 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 標記介面,因此,它會記錄所有應用程式 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 查詢限制為僅返回五個結果,同時按升序對 CustomersfirstName 排序。為此,您可以定義一個自定義 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 儲存庫約定來實現相同的效果。例如,可以按如下方式定義相同的查詢

示例 17. 使用約定的 CustomerRepository
interface CustomerRepository extends CrudRepository<Customer, Long> {

  @Limit(5)
  List<Customer> findDistinctByLastNameLikeOrderByFirstNameDesc(String lastName);

}

但是,如果您無法控制應用程式 CustomerRepository 介面定義,那麼 QueryPostProcessor(即 OrderedLimitedCustomerByLastNameQueryPostProcessor)會很方便。

如果您希望確保 LoggingQueryPostProcessor 始終位於其他應用程式定義的 QueryPostProcessors 之後,這些 QueryPostProcessors 可能已在 Spring ApplicationContext 中宣告和註冊為 bean,則可以透過覆蓋 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,並按任何順序將它們應用於所有或特定的應用程式儲存庫介面,並且可以透過向 postProcess(..) 方法回撥提供提供的引數來儘可能細化。

11. 函式執行的註釋支援

Spring Data for Pivotal GemFire 包括註釋支援,以簡化使用 Pivotal GemFire 函式執行

在底層,Pivotal GemFire API 提供了類來實現和註冊 Pivotal GemFire 函式,這些函式部署在 Pivotal GemFire 伺服器上,然後可以由其他對等成員應用程式或遠端從快取客戶端呼叫這些函式。

函式可以並行執行,分佈在叢集中的多個 Pivotal GemFire 伺服器中,使用 Map-Reduce 模式聚合結果併發送回呼叫者。函式還可以被指定在單個伺服器或區域上執行。Pivotal GemFire API 支援使用各種預定義範圍(在區域上、在成員(組中)、在伺服器上等)來遠端執行函式。與任何 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 實現,以將結果傳送回客戶端。此外,如果在區域上執行函式,則 FunctionContext 實際上是 RegionFunctionContext 的例項,它提供其他資訊,例如呼叫函式的目標區域、與 Execution 關聯的任何過濾器(一組特定鍵)等。如果區域是 PARTITION 區域,則函式應使用 PartitionRegionHelper 提取本地資料集。

透過使用 Spring,您可以編寫一個簡單的 POJO,並使用 Spring 容器將一個或多個 POJO 的公有方法繫結到函式。用作函式的 POJO 方法的簽名通常必須符合客戶端的執行引數。但是,在區域執行的情況下,還可以提供區域資料(如果區域是 PARTITION 區域,則資料可能儲存在本地分割槽中)。

此外,函式可能需要應用的過濾器(如果存在)。這表明客戶端和伺服器共享呼叫引數的契約,但方法簽名可能包括其他引數以傳遞 FunctionContext 提供的值。一種可能性是客戶端和伺服器共享一個公共介面,但這並不是嚴格要求的。唯一的約束是,在解析其他引數後,方法簽名包括與呼叫函式時相同的呼叫引數序列。

例如,假設客戶端提供 Stringint 作為呼叫引數。它們在 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) { ... }

一般規則是,一旦解析了任何附加引數(即,區域資料和過濾器),剩餘的引數必須與預期的 Function 方法引數在順序和型別上完全對應。方法的返回型別必須是 void 或可序列化的型別(如 java.io.SerializableDataSerializablePdxSerializable)。後者也是呼叫引數的要求。

區域資料通常應定義為 Map,以方便單元測試,但如有必要,也可以是 Region 型別。如前例所示,如果需要控制如何將結果返回給客戶端,也可以傳遞 FunctionContext 本身或 ResultSender

11.2.1. 函式實現的註釋

以下示例展示瞭如何使用 SDG 的 Function 註釋將 POJO 方法公開為 Pivotal GemFire Function

@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 Function 都使用 @GemfireFunction 註釋。在前一個示例中,使用了 Spring 的 @Component 註釋,但你可以使用 Spring 支援的任何方法(例如 XML 配置或在使用 Spring Boot 時使用 Java 配置類)註冊 bean。這允許 Spring 容器建立此類的例項,並將其包裝在 PojoFunctionWrapper 中。Spring 為使用 @GemfireFunction 註釋的每個方法建立一個包裝器例項。每個包裝器例項共享同一個目標物件例項,以呼叫相應的方法。

POJO Function 類是 Spring bean 的事實可能帶來其他好處。由於它與 Pivotal GemFire 元件(例如快取和區域)共享 ApplicationContext,因此如有必要,可以將這些元件注入到類中。

Spring 建立包裝器類,並將 Function 註冊到 Pivotal GemFire 的 FunctionService 中。用於註冊每個 Function 的 Function ID 必須是唯一的。透過使用約定,它預設為簡單(不合格)的方法名稱。可以使用 @GemfireFunction 註釋的 id 屬性顯式定義名稱。

@GemfireFunction 註釋還提供了其他配置屬性:HAoptimizedForWrite,它們對應於 Pivotal GemFire 的 Function 介面定義的屬性。

如果 POJO Function 方法的返回型別是 void,則 hasResult 屬性會自動設定為 false。否則,如果方法返回一個值,則 hasResult 屬性會設定為 true。即使對於 void 方法返回型別,GemfireFunction 註釋的 hasResult 屬性也可以設定為 true 以覆蓋此約定,如之前所示的 functionWithContext 方法中所示。據推測,你的目的是直接使用 ResultSender 向呼叫者傳送結果。

最後,GemfireFunction 註釋支援 requiredPermissions 屬性,該屬性指定執行函式所需的許可權。預設情況下,所有函式都需要 DATA:WRITE 許可權。該屬性接受一個字串陣列,允許您根據應用程式和/或函式 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 可以是區域的名稱或 {data-store-javadoc]/org/apache/geode/security/ResourcePermission.Target.html[ResourcePermission.Target] 列舉值之一(可選)。最後,KeyTarget 區域中的有效鍵(如果指定)。

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. 執行函式

呼叫遠端函式的程序需要提供函式的 ID、呼叫引數、執行目標(onRegiononServersonServeronMemberonMembers)和(可選)過濾器集。透過使用 Spring Data for Pivotal GemFire,您只需要定義一個受註釋支援的介面。Spring 為該介面建立一個動態代理,該代理使用 FunctionService 建立 Execution、呼叫 Execution,並(如果需要)將結果強制轉換為定義的返回型別。此技術類似於 Spring Data for Pivotal GemFire 的 Repository 擴充套件工作的方式。因此,一些配置和概念應該是熟悉的。

通常,單個介面定義對映到多個函式執行,每個函式執行對應於介面中定義的一個方法。

11.3.1. 函式執行的註釋

為了支援客戶端函式執行,提供了以下 SDG 函式註解:@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);

}

預設情況下,函式 ID 是簡單(不合格)的方法名稱。@FunctionId 註解可用於將此呼叫繫結到不同的函式 ID。

11.3.2. 啟用註釋處理

客戶端使用 Spring 的類路徑元件掃描功能來發現帶註解的介面。要在 XML 中啟用函式執行註解處理,請在 XML 配置中插入以下元素

<gfe-data:function-executions base-package="org.example.myapp.gemfire.functions"/>

function-executions 元素在 gfe-data XML 名稱空間中提供。base-package 屬性是必需的,以避免掃描整個類路徑。可以提供其他過濾器,如 Spring 中所述 參考文件

或者,您可以按如下方式註釋您的 Java 配置類

@EnableGemfireFunctionExecutions(basePackages = "org.example.myapp.gemfire.functions")

11.4. 程式化函式執行

使用上一節中定義的函式執行帶註解的介面,只需將您的介面自動裝配到將呼叫函式的應用程式 Bean 中即可

@Component
public class MyApplication {

    @Autowired
    FunctionExecution functionExecution;

    public void doSomething() {
         functionExecution.doIt("hello", 123);
    }
}

或者,您可以直接使用函式執行模板。在以下示例中,GemfireOnRegionFunctionTemplate 建立了一個 onRegion 函式 Execution

示例 19. 使用 GemfireOnRegionFunctionTemplate
Set<?, ?> myFilter = getFilter();
Region<?, ?> myRegion = getRegion();
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(myRegion);
String result = template.executeAndExtract("someFunction", myFilter, "hello", "world", 1234);

在內部,函式 Executions 始終返回一個 ListexecuteAndExtract 假設一個包含結果的單例 List,並嘗試將該值強制轉換為請求的型別。還有一個 execute 方法,它按原樣返回 List。第一個引數是函式 ID。過濾器引數是可選的。其餘引數是一個可變引數 List

11.5. 使用 PDX 的函式執行

在將 Spring Data for Pivotal GemFire 的函式註解支援與 Pivotal GemFire 的 PDX 序列化結合使用時,有一些邏輯問題需要記住。

正如本節前面所解釋的,並且舉例來說,您通常應該使用帶 Spring Data for Pivotal GemFire 函式註解註釋的 POJO 類來定義 Pivotal GemFire 函式,如下所示

public class OrderFunctions {

  @GemfireFunction(...)
  Order process(@RegionData data, Order order, OrderSource orderSourceEnum, Integer count) { ... }

}
Integer 型別 count 引數是任意的,Order 類和 OrderSource 列舉的分離也是任意的,將兩者結合起來可能是合理的。但是,以這種方式設定引數是為了演示 PDX 上下文中函式執行存在的問題。

您的 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
  ...
}

當然,您可以定義一個函式 Execution 介面來呼叫“process”Pivotal GemFire 伺服器函式,如下所示

@OnServer
public interface OrderProcessingFunctions {
  Order process(Order order, OrderSource orderSourceEnum, Integer count);
}

顯然,此 process(..) Order 函式是從客戶端使用 ClientCache 例項(即 <gfe:client-cache/>)呼叫的。這意味著函式引數也必須是可序列化的。在群集中對等成員函式(如 @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"/>

這樣做會導致從快取(即區域)讀取的所有值以及在客戶端和伺服器(或對等方)之間傳遞的資訊保持序列化的形式,包括但不限於函式引數。

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 型別,無論它們是否已顯式配置(即使用 ReflectionBasedAutoSerializer、正則表示式模式和 classes 引數註冊,或由“自定義”Pivotal GemFire PdxSerializer 處理),儘管 Java 列舉實現了 java.io.Serializable

因此,當您在註冊了 Pivotal GemFire 函式(包括 Spring Data for Pivotal GemFire 函式註釋的 POJO 類)的 Pivotal GemFire 伺服器上將 pdx-read-serialized 設定為 true 時,在呼叫函式 Execution 時可能會遇到意外的行為。

呼叫函式時,您可能會傳遞以下引數

orderProcessingFunctions.process(new Order(123, customer, LocalDateTime.now(), items), OrderSource.ONLINE, 400);

然而,伺服器上的 Pivotal GemFire 函式獲取以下內容

process(regionData, order:PdxInstance, :PdxInstanceEnum, 400);

OrderOrderSource 已作為 PDX 例項 傳遞給函式。同樣,這一切都發生在 pdx-read-serialized 設定為 true 的情況下,這在 Pivotal GemFire 伺服器與多個不同客戶端(例如,Java 客戶端和本機客戶端的組合,如 C/C++、C# 等)互動的情況下可能是必要的。

這與 Spring Data for Pivotal GemFire 強型別函式註釋的 POJO 類方法簽名背道而馳,在該簽名中,您合理地期望應用程式域物件型別,而不是 PDX 序列化例項。

因此,Spring Data for Pivotal GemFire 包含增強的函式支援,以自動將 PDX 型別的方法引數轉換為函式方法簽名(引數型別)定義的所需應用程式域物件型別。

但是,這也要求您在註冊和使用 Spring Data for Pivotal GemFire 函式註釋的 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 謹慎地不轉換您的函式引數,如果您將函式引數泛型化處理或作為 Pivotal GemFire 的 PDX 型別之一處理,如下所示

@GemfireFunction
public Object genericFunction(String value, Object domainObject, PdxInstanceEnum enum) {
 ...
}

Spring Data for Pivotal GemFire 僅當相應的應用程式域型別在類路徑上並且函式註釋的 POJO 方法期望它時,才將 PDX 型別的資料轉換為相應的應用程式域型別。

有關自定義、組合的特定於應用程式的 Pivotal GemFire PdxSerializers 以及基於方法簽名的適當 POJO 函式引數型別處理的良好示例,請參閱 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 配置中宣告或定義 LuceneIndex,在 @Configuration 類中,如下例所示

@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 整合和支援有一些限制。

首先,只能在 Pivotal GemFire PARTITION 區域上建立 LuceneIndex

其次,必須在應用 LuceneIndex 的區域之前建立所有 LuceneIndexes

為了幫助確保在 Spring 容器中定義的所有已宣告 LuceneIndexes 在其應用的區域之前建立,SDG 包含 org.springframework.data.gemfire.config.support.LuceneIndexRegionBeanFactoryPostProcessor。您可以在 XML 配置中使用 <bean class="org.springframework.data.gemfire.config.support.LuceneIndexRegionBeanFactoryPostProcessor"/> 註冊此 Spring BeanFactoryPostProcessoro.s.d.g.config.support.LuceneIndexRegionBeanFactoryPostProcessor 僅可在使用 SDG XML 配置時使用。有關 Spring 的 BeanFactoryPostProcessors 的更多詳細資訊,請參閱 此處

這些 Pivotal GemFire 限制將來可能不適用,這就是 SDG LuceneIndexFactoryBean API 直接引用區域而不是僅引用區域路徑的原因。

當您希望在應用程式生命週期的稍後階段根據需求在具有資料的現有區域上定義LuceneIndex時,這樣做更理想。在可能的情況下,SDG 努力堅持強型別物件。但是,目前,您必須使用regionPath屬性來指定應用LuceneIndex的區域。

此外,在前面的示例中,請注意Books區域 Bean 定義上存在 Spring 的@DependsOn註釋。這會從Books區域 Bean 到bookTitleIndexLuceneIndex Bean 定義建立一個依賴關係,確保在應用LuceneIndex的區域之前建立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 異常層次結構,特別是許多現代資料訪問操作涉及多個儲存或儲存庫。

此外,SDG 的LuceneOperations介面可以保護您的應用程式免受底層 Pivotal GemFire 或 Apache Lucene API 在發生時引入的破壞介面的更改的影響。

但是,提供僅使用 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 投影基礎設施將查詢結果應用於給定投影型別的例項。

此外,該模板將分頁的 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());
    }
}

此外,根據您的應用程式檢視,您可能有一個單一的介面來將人員表示為客戶,如下所示

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;
}

那麼您可以查詢人員作為人員物件,如下所示

List<Person> people = luceneTemplate.query("lastName: D*", "lastName", Person.class);

或者,您可以查詢客戶型別的頁面,如下所示

Page<Customer> customers = luceneTemplate.query("lastName: D*", "lastName", 100, 20, Customer.class);

然後可以使用頁面來獲取結果的各個頁面,如下所示

List<Customer> firstPage = customers.getContent();

方便的是,Spring Data Commons 頁面介面還實現了java.lang.Iterable<T>,使其易於遍歷內容。

Spring Data Commons 投影基礎架構的唯一限制是投影型別必須是一個介面。但是,可以擴充套件提供的 SDC 投影基礎架構並提供一個自定義的 ProjectionFactory,它使用 CGLIB 來生成代理類作為投影實體。

您可以使用 setProjectionFactory(:ProjectionFactory) 在 Lucene 模板上設定一個自定義的 ProjectionFactory

12.2. 註釋配置支援

最後,Spring Data for Pivotal GemFire 為 LuceneIndexes 提供了註釋配置支援。

最終,SDG Lucene 支援將進入 Pivotal GemFire 的儲存庫基礎架構擴充套件,以便可以將 Lucene 查詢表示為應用程式 儲存庫 介面上的方法,這與 OQL 支援 現在的工作方式非常相似。

但是,在此期間,如果您想方便地表示 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 區域。

根據我們對 Person 類的早期定義,SDG 註釋配置支援查詢 Person 實體類定義,並確定人員儲存在名為 “People” 的 PARTITION 區域中,並且 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 主類進行引導並託管你的應用程式。

Pivotal GemFire 不是應用程式伺服器。此外,在涉及 Pivotal GemFire 快取配置時,使用此方法存在限制。

13.1. 使用 Pivotal GemFire 引導使用 Gfsh 啟動的 Spring 上下文

為了在使用 Gfsh 啟動 Pivotal GemFire 伺服器時在 Pivotal GemFire 中引導 Spring ApplicationContext,你必須使用 Pivotal GemFire 的 initalizer 功能。initializer 塊可以宣告一個應用程式回撥,該回調在 Pivotal GemFire 初始化快取後啟動。

initializer 在 initializer 元素中宣告,方法是使用 Pivotal GemFire 本機 cache.xml 的最小片段。為了引導 Spring ApplicationContext,需要一個 cache.xml 檔案,這與引導配置了元件掃描的 Spring ApplicationContext(例如 <context:component-scan base-packages="…​"/>)所需的 Spring XML 配置的最小片段非常相似。

幸運的是,框架已經方便地提供了這樣一個 initializer: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 類類似的約定,後者用於在 Web 應用程式中引導 Spring ApplicationContext,其中 ApplicationContext 配置檔案使用 contextConfigLocations Servlet 上下文引數指定。

此外,SpringContextBootstrappingInitializer 類還可以與 basePackages 引數一起使用,以指定一個包含適當註釋的應用程式元件的逗號分隔的基本包列表。Spring 容器搜尋這些元件以查詢並建立類路徑中的 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>

然後,在以命令列選項形式指定正確配置和構建的 CLASSPATHcache.xml 檔案(如前所述)以在 Gfsh 中啟動 Pivotal GemFire 伺服器時,命令列如下所示

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 已提供對自動連線 Pivotal GemFire 元件(例如 CacheListenersCacheLoadersCacheWriters 等)的支援,這些元件由 Pivotal GemFire 在 cache.xml 中宣告和建立,方法是使用 SDG 的 WiringDeclarableSupport 類,如 使用自動連線和註釋進行配置 中所述。但是,這僅在 Spring 執行自舉時有效(即當 Spring 自舉 Pivotal GemFire 時)。

當 Pivotal GemFire 自舉 Spring ApplicationContext 時,這些 Pivotal GemFire 應用程式元件不會被注意到,因為 Spring ApplicationContext 尚未存在。Spring ApplicationContext 直到 Pivotal GemFire 呼叫初始化程式塊才建立,而該塊僅在所有其他 Pivotal GemFire 元件(快取、區域等)已建立並初始化後才發生。

為了解決這個問題,引入了一個新的 LazyWiringDeclarableSupport 類。此新類瞭解 Spring ApplicationContext。此抽象基類的目的是,任何實現類都會註冊自身,以便由 Pivotal GemFire 在呼叫初始化程式後最終建立的 Spring 容器進行配置。從本質上講,這給了 Pivotal GemFire 應用程式元件一個機會,以便使用 Spring 容器中定義的 Spring bean 進行配置和自動裝配。

為了讓 Spring 容器自動裝配 Pivotal GemFire 應用程式元件,您應該建立一個應用程式類,該類擴充套件 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 示例 儲存庫中。

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 從命令列啟動。如果正確設定了類路徑,您還可以直接對生成的工件使用 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 元件掃描執行類路徑 元件

快取配置定義了 Pivotal GemFire 快取、區域,以及出於說明目的,充當記錄器的 CacheListener

主要 Bean 是 HelloWorldCommandProcessor,它們依賴於 GemfireTemplate 與分散式結構進行互動。這兩個類都使用註釋來定義其依賴關係和生命週期回撥。

資源

除了此參考文件外,還有許多其他資源可以幫助您瞭解如何將 {data-store-product-name} 與 Spring Framework 一起使用。本節列出了這些其他第三方資源。

附錄

附錄 A:名稱空間參考

<repositories /> 元素

<repositories /> 元素觸發 Spring 資料儲存庫基礎設施的設定。最重要的屬性是 base-package,它定義要掃描 Spring 資料儲存庫介面的包。請參閱“[repositories.create-instances.spring]”。下表描述了 <repositories /> 元素的屬性

表 6. 屬性
名稱 說明

base-package

在自動檢測模式下,定義要掃描以擴充套件 *Repository(實際介面由特定的 Spring 資料模組確定)的儲存庫介面的包。配置的包下的所有包也會被掃描。允許使用萬用字元。

repository-impl-postfix

定義自動檢測自定義儲存庫實現的字尾。名稱以配置的字尾結尾的類被視為候選。預設為 Impl

query-lookup-strategy

確定用於建立查詢器查詢的策略。有關詳細資訊,請參閱“[repositories.query-methods.query-lookup-strategies]”。預設為 create-if-not-found

named-queries-location

定義搜尋包含外部定義查詢的屬性檔案的位置。

consider-nested-repositories

是否應考慮巢狀儲存庫介面定義。預設為 false

附錄 B:填充器名稱空間參考

<populator /> 元素

<populator /> 元素允許透過 Spring 資料儲存庫基礎設施填充資料儲存。[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

表示無返回值。

基本型別

Java 基本型別。

包裝型別

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 建構函式或工廠方法引數的型別

公開一個建構函式或 ….of(…)/….valueOf(…) 工廠方法,採用 Streamable 作為引數的型別。有關詳細資訊,請參閱 [repositories.collections-and-iterables.streamable-wrapper]

Vavr SeqListMapSet

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.