© 2010-2022 原作者。
您可以複製此文件供自己使用,也可以分發給其他人,但前提是您不收取任何費用,並且每個副本(無論是印刷版還是電子版)都包含此版權宣告。 |
前言
Spring Data for Apache Geode 側重於將 Spring Framework 的強大、非侵入式程式設計模型和概念與 Apache Geode 整合,以簡化使用 Apache Geode 作為資料管理解決方案時 Java 應用程式的配置和開發。
本文件假設您已經對 Spring Framework 和 Apache Geode 的核心概念有一定的瞭解和熟悉。
儘管我們盡一切努力確保本文件全面完整且無誤,但有些主題超出了本文件的範圍,可能需要更多解釋(例如,使用 HA 進行分割槽的資料分佈管理,同時保持一致性)。此外,可能還存在一些排版錯誤。如果您發現錯誤,甚至更嚴重的錯誤,請透過在 JIRA 中建立相應的 問題,將這些問題告知 Spring Data 團隊。
1. 簡介
Spring Data for Apache Geode 參考指南解釋瞭如何使用 Spring Framework 配置和開發使用 Apache Geode 的應用程式。它介紹了基本概念,並提供了大量示例來幫助您快速入門。
2. 需求
Spring Data for Apache Geode 需要 Java 8.0、Spring Framework 5 和 Apache Geode 1.9.0。
3. 新功能
從 1.2.0.RELEASE 版本開始,這個專案以前稱為 Spring GemFire,現在更名為 Spring Data for Apache Geode,以反映它現在是 Spring Data 專案的模組,並且構建在 Apache Geode 之上。 |
3.1. 2.0 版本新增功能
-
升級到 Apache Geode 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 時輕鬆便捷地表達客戶端和伺服器之間鍵和值的興趣。 -
在註釋配置模型中添加了對 Off-Heap、Redis 介面卡和 Apache Geode 新安全框架的支援。
參考指南
4. 文件結構
以下章節解釋了 Spring Data for Apache Geode 提供的核心功能
-
使用 Spring 容器引導 Apache Geode 描述了為配置、初始化和訪問 Apache Geode 快取、區域和相關分散式系統元件提供的配置支援。
-
使用 Apache Geode API 解釋了 Apache Geode API 與 Spring 中提供的各種資料訪問功能(如基於模板的資料訪問、異常轉換、事務管理和快取)之間的整合。
-
使用 Apache Geode 序列化 描述了對 Apache Geode 管理物件的序列化和反序列化的增強。
-
POJO 對映 描述了使用 Spring Data 將儲存在 Apache Geode 中的 POJO 進行持久化對映。
-
Spring Data for Apache Geode 儲存庫 描述瞭如何使用 Spring Data 儲存庫來訪問儲存在 Apache Geode 中的資料,方法是使用基本的 CRUD 和簡單的查詢操作。
-
函式執行的註解支援 描述瞭如何使用註解建立和使用 Apache Geode 函式來執行分散式計算,這些計算在資料所在的位置進行。
-
連續查詢 (CQ) 描述瞭如何使用 Apache Geode 的連續查詢 (CQ) 功能來處理基於興趣的事件流,該興趣是在 Apache Geode 的 OQL(物件查詢語言)中定義和註冊的。
-
在 Apache Geode 中引導 Spring ApplicationContext 描述瞭如何使用
Gfsh
配置和引導在 Apache Geode 伺服器中執行的 SpringApplicationContext
。 -
示例應用程式 描述了與分發一起提供的示例,以說明 Spring Data for Apache Geode 中提供的各種功能。
5. 使用 Spring 容器引導 Apache Geode
Spring Data for Apache Geode 使用 Spring IoC 容器提供 Apache Geode 記憶體資料網格 (IMDG) 的完整配置和初始化。該框架包含幾個類來幫助簡化 Apache Geode 元件的配置,包括:快取、區域、索引、磁碟儲存、函式、WAN 閘道器、永續性備份以及其他幾個分散式系統元件,以支援各種應用程式用例,而無需付出太多努力。
本節假設您對 Apache Geode 有基本瞭解。有關更多資訊,請參閱 Apache Geode 產品文件。 |
5.1. 使用 Spring 比 Apache Geode cache.xml
的優勢
Spring Data for Apache Geode 的 XML 名稱空間支援 Apache Geode 記憶體資料網格 (IMDG) 的完整配置。XML 名稱空間是兩種在 Spring 上下文中配置 Apache Geode 的方法之一,以便在 Spring 容器中正確管理 Apache Geode 的生命週期。在 Spring 上下文中配置 Apache Geode 的另一種方法是使用 基於註解的配置。
雖然出於遺留原因,對 Apache Geode 的原生 cache.xml
的支援仍然存在,但使用 XML 配置的 Apache Geode 應用程式開發人員建議在 Spring XML 中完成所有操作,以利用 Spring 提供的許多出色功能,例如模組化 XML 配置、屬性佔位符和覆蓋、SpEL (Spring 表示式語言) 和環境配置檔案。在 XML 名稱空間的背後,Spring Data for Apache Geode 廣泛使用 Spring 的 FactoryBean
模式來簡化 Apache Geode 元件的建立、配置和初始化。
Apache Geode 提供了幾個回撥介面,例如 CacheListener
、CacheLoader
和 CacheWriter
,這些介面允許開發人員新增自定義事件處理程式。使用 Spring 的 IoC 容器,您可以將這些回撥配置為普通的 Spring bean,並將它們注入到 Apache Geode 元件中。這是對原生 cache.xml
的重大改進,原生 cache.xml
提供的配置選項相對有限,並且要求回撥實現 Apache Geode 的 Declarable
介面(請參閱 連線 Declarable
元件,瞭解如何在 Spring 的容器中使用 Declarables
)。
此外,IDE(如 Spring Tool Suite (STS))為 Spring XML 名稱空間提供了出色的支援,包括程式碼補全、彈出式註釋和即時驗證。
5.2. 使用核心名稱空間
為了簡化配置,Spring Data for Apache Geode 提供了一個專門的 XML 名稱空間來配置核心 Apache Geode 元件。可以使用 Spring 的標準 <bean>
定義直接配置 bean。但是,所有 bean 屬性都透過 XML 名稱空間公開,因此使用原始 bean 定義幾乎沒有好處。
有關 Spring 中基於 XML 架構的配置的更多資訊,請參閱 Spring 框架參考文件中的附錄。 |
Spring Data Repository 支援使用單獨的 XML 名稱空間。有關如何配置 Spring Data for Apache Geode Repositories 的更多資訊,請參閱Spring Data for Apache Geode Repositories。 |
要使用 Spring Data for Apache Geode 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/geode" (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/geode https://www.springframework.org/schema/geode/spring-geode.xsd (3)
">
<bean id ... >
<gfe:cache ...> (4)
</beans>
1 | Spring Data for Apache Geode XML 名稱空間字首。任何名稱都可以,但在整個參考文件中,使用 gfe 。 |
2 | XML 名稱空間字首對映到 URI。 |
3 | XML 名稱空間 URI 位置。請注意,即使位置指向外部地址(確實存在且有效),Spring 也會在本地解析模式,因為它包含在 Spring Data for Apache Geode 庫中。 |
4 | 使用帶有 gfe 字首的 XML 名稱空間的示例宣告。 |
您可以將預設名稱空間從
|
5.3. 使用資料訪問名稱空間
除了核心 XML 名稱空間 (gfe
) 之外,Spring Data for Apache Geode 還提供了一個數據訪問 XML 名稱空間 (gfe-data
),它主要用於簡化 Apache Geode 客戶端應用程式的開發。此名稱空間目前包含對 Apache Geode Repositories 和 Function execution 的支援,以及一個 <datasource>
標籤,它提供了一種方便的方式來連線到 Apache Geode 叢集。
5.3.1. 連線 Apache Geode 的簡便方法
對於許多應用程式來說,使用預設值連線到 Apache Geode 資料網格就足夠了。Spring Data for Apache Geode 的 <datasource>
標籤提供了一種簡單的方式來訪問資料。資料來源建立了一個 ClientCache
和連線 Pool
。此外,它查詢叢集伺服器以獲取所有現有的根 Region,併為每個根 Region 建立一個(空的)客戶端 Region 代理。
<gfe-data:datasource>
<locator host="remotehost" port="1234"/>
</gfe-data:datasource>
<datasource>
標籤在語法上類似於 <gfe:pool>
。它可以使用一個或多個巢狀的 locator
或 server
元素進行配置,以連線到現有的資料網格。此外,還支援所有可用於配置 Pool 的屬性。此配置會自動為連線到 Locator 的叢集成員上定義的每個 Region 建立客戶端 Region bean,因此它們可以被 Spring Data 對映註釋 (GemfireTemplate
) 無縫引用,並自動注入到應用程式類中。
當然,您可以顯式地配置客戶端 Region。例如,如果您想在本地記憶體中快取資料,如下例所示
<gfe-data:datasource>
<locator host="remotehost" port="1234"/>
</gfe-data:datasource>
<gfe:client-region id="Example" shortcut="CACHING_PROXY"/>
5.4. 配置快取
要使用 Apache Geode,您需要建立一個新的快取或連線到現有的快取。使用當前版本的 Apache Geode,您每個 VM(更嚴格地說,每個 ClassLoader
)只能有一個開啟的快取。在大多數情況下,快取應該只建立一次。
本節描述了對等 Cache 成員的建立和配置,適用於點對點 (P2P) 拓撲和快取伺服器。Cache 成員也可以在獨立應用程式和整合測試中使用。但是,在典型的生產系統中,大多數應用程式程序充當快取客戶端,建立 ClientCache 例項。這在 配置 Apache Geode ClientCache 和 客戶端 Region 部分進行了描述。
|
可以使用以下簡單宣告建立具有預設配置的對等 Cache
:
<gfe:cache/>
在 Spring 容器初始化期間,任何包含此快取定義的 `ApplicationContext` 會註冊一個 `CacheFactoryBean`,該工廠建立名為 `gemfireCache` 的 Spring Bean,它引用一個 Apache Geode `Cache` 例項。此 Bean 引用一個已存在的 `Cache`,或者如果不存在則建立一個新的 `Cache`。由於沒有指定其他屬性,新建立的 `Cache` 會應用預設的快取配置。
所有依賴 `Cache` 的 Spring Data for Apache Geode 元件都遵循此命名約定,因此您無需顯式宣告 `Cache` 依賴項。如果您願意,可以使用各種 SDG XML 名稱空間元素提供的 `cache-ref` 屬性來顯式宣告依賴項。此外,您可以使用 `id` 屬性覆蓋快取的 Bean 名稱,如下所示
<gfe:cache id="myCache"/>
可以使用 Spring 全面配置 Apache Geode `Cache`。但是,Apache Geode 的原生 XML 配置檔案 `cache.xml` 也受支援。對於需要原生配置 Apache Geode 快取的情況,可以使用 `cache-xml-location` 屬性提供對 Apache Geode XML 配置檔案的引用,如下所示
<gfe:cache id="cacheConfiguredWithNativeCacheXml" cache-xml-location="classpath:cache.xml"/>
在此示例中,如果需要建立快取,它會使用類路徑根目錄中名為 `cache.xml` 的檔案來配置它。
該配置利用 Spring 的 Resource 抽象來定位檔案。`Resource` 抽象允許使用各種搜尋模式,具體取決於執行時環境或資源位置中指定的(如果有)字首。
|
除了引用外部 XML 配置檔案之外,您還可以指定 Apache Geode 系統 屬性,這些屬性使用 Spring 的任何 `Properties` 支援功能。
例如,您可以使用 `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/geode"
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/geode https://www.springframework.org/schema/geode/spring-geode.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>
建議使用屬性檔案將特定於環境的設定外部化到應用程式配置之外。
快取設定僅在需要建立新快取時應用。如果虛擬機器中已存在開啟的快取,則會忽略這些設定。 |
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:jndi-binding jndi-name="myDataSource" type="ManagedDataSource"/> (8)
</gfe:cache>
1 | 屬性支援各種快取選項。有關此示例中顯示的任何內容的更多資訊,請參閱 Apache Geode 產品文件。close 屬性決定在 Spring 應用程式上下文關閉時是否應關閉快取。預設值為 true 。但是,對於多個應用程式上下文使用快取的用例(在 Web 應用程式中很常見),請將此值設定為 false 。 |
2 | 將 enable-auto-reconnect 屬性設定為 true (預設值為 false )允許斷開的 Apache Geode 成員自動重新連線並重新加入 Apache Geode 叢集。有關更多詳細資訊,請參閱 Apache Geode 產品文件。 |
3 | 將 use-bean-factory-locator 屬性設定為 true (預設值為 false )僅在使用 Spring(XML)配置元資料和 Apache Geode cache.xml 配置 Apache Geode 快取節點(無論是客戶端還是對等節點)時才適用。此選項允許在 cache.xml 中表達的 Apache Geode 元件(例如 CacheLoader )使用 Spring 應用程式上下文中定義的 bean(例如 DataSource )自動裝配。此選項通常與 cache-xml-location 結合使用。 |
4 | 將 use-cluster-configuration 屬性設定為 true (預設值為 false )使 Apache Geode 成員能夠從定位器檢索通用的共享基於叢集的配置。有關更多詳細資訊,請參閱 Apache Geode 產品文件。 |
5 | 使用 bean 引用宣告 TransactionListener 回撥的示例。引用的 bean 必須實現 TransactionListener。可以實現 TransactionListener 來處理與事務相關的事件(例如 afterCommit 和 afterRollback)。 |
6 | 使用內部 bean 宣告宣告 TransactionWriter 回撥的示例。該 bean 必須實現 TransactionWriter。TransactionWriter 是一個回撥,可以否決事務。 |
7 | 這是一個使用 Bean 引用宣告 GatewayConflictResolver 回撥的示例。引用的 Bean 必須實現 https://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/util/GatewayConflictResolver.html [GatewayConflictResolver]。GatewayConflictResolver 是一個 Cache 級別的外掛,用於決定如何處理來自其他系統並透過 WAN 閘道器到達的事件,該閘道器提供分散式 Region 建立服務。 |
8 | 宣告一個 JNDI 繫結,以將外部資料來源註冊到 Apache Geode 事務中。 |
啟用 PDX 序列化
上面的示例包含許多與 Apache Geode 的增強序列化框架 PDX 相關的屬性。雖然本參考指南無法全面討論 PDX,但重要的是要注意,PDX 是透過註冊 PdxSerializer
來啟用的,該序列化器由設定 pdx-serializer
屬性指定。
Apache Geode 提供了一個實現類 (org.apache.geode.pdx.ReflectionBasedAutoSerializer
),它使用 Java 反射。但是,開發人員通常會提供自己的實現。該屬性的值只是一個對實現 PdxSerializer
介面的 Spring Bean 的引用。
有關序列化支援的更多資訊,請參閱 使用 Apache Geode 序列化。
啟用自動重新連線
將 <gfe:cache enable-auto-reconnect="[true|false*]>
屬性設定為 true
時,應謹慎操作。
通常,僅在使用 Spring Data for Apache Geode 的 XML 名稱空間配置和引導新增到叢集中的新非應用程式 Apache Geode 伺服器時,才應啟用“自動重新連線”。換句話說,當 Spring Data for Apache Geode 用於開發和構建 Apache Geode 應用程式時,該應用程式恰好也是 Apache Geode 叢集的同級 Cache
成員,則不應啟用“自動重新連線”。
此限制的主要原因是,大多數 Apache Geode 應用程式使用對 Apache Geode Cache
或 Region 的引用來執行資料訪問操作。這些引用由 Spring 容器“注入”到應用程式元件(例如儲存庫)中,供應用程式使用。當同級成員被強制從叢集的其餘部分斷開連線時,可能是因為同級成員變得無響應或網路分割槽將一個或多個同級成員分離到一個太小而無法作為獨立分散式系統執行的組中,同級成員將關閉,並且所有 Apache Geode 元件引用(快取、Region 等)將變得無效。
本質上,每個同級成員中的當前強制斷開連線處理邏輯會從頭開始拆卸系統。JGroups 堆疊關閉,分散式系統進入關閉狀態,最後快取關閉。實際上,所有記憶體引用都已過時並丟失。
在從分散式系統斷開連線後,同級成員進入“重新連線”狀態,並定期嘗試重新加入分散式系統。如果同級成員成功重新連線,則成員將從現有成員重建其對分散式系統的“檢視”,並接收新的分散式系統 ID。此外,所有快取、Region 和其他 Apache Geode 元件都將重建。因此,所有可能已由 Spring 容器注入到應用程式中的舊引用現在已過時且不再有效。
Apache Geode 不保證(即使使用 Apache Geode 公共 Java API)應用程式快取、區域或其他元件引用會透過重新連線操作自動重新整理。因此,Apache Geode 應用程式必須注意重新整理自己的引用。
不幸的是,沒有辦法收到斷開連線事件的通知,以及隨後重新連線事件的通知。如果是這樣,您將有一個清晰的方法來知道何時呼叫 `ConfigurableApplicationContext.refresh()`,即使它適用於應用程式這樣做,這也是為什麼 Apache Geode 的此“功能”不推薦用於對等 `Cache` 應用程式的原因。
有關“自動重新連線”的更多資訊,請參閱 Apache Geode 的 產品文件。
使用基於叢集的配置
Apache Geode 的叢集配置服務是任何加入叢集的對等成員透過使用定位器維護的共享持久配置來獲取叢集“一致檢視”的便捷方式。使用基於叢集的配置可確保對等成員的配置在成員加入時與 Apache Geode 分散式系統相容。
Spring Data for Apache Geode 的此功能(將 `use-cluster-configuration` 屬性設定為 `true`)的工作方式與 `cache-xml-location` 屬性相同,只是 Apache Geode 配置元資料的來源來自網路透過定位器,而不是本地 `cache.xml` 檔案駐留在本地檔案系統中。
所有 Apache Geode 本地配置元資料,無論是來自 `cache.xml` 還是來自叢集配置服務,都會在任何 Spring(XML)配置元資料之前應用。因此,Spring 的配置用於“增強”本地 Apache Geode 配置元資料,並且很可能特定於應用程式。
同樣,要啟用此功能,請在 Spring XML 配置中指定以下內容
<gfe:cache use-cluster-configuration="true"/>
雖然某些 Apache Geode 工具(如 *Gfsh*)在進行類似模式的更改(例如,`gfsh>create region --name=Example --type=PARTITION`)時會“記錄”其操作,但 Spring Data for Apache Geode 的配置元資料不會被記錄。直接使用 Apache Geode 的公共 Java API 時也是如此。它也不會被記錄。 |
有關 Apache Geode 的叢集配置服務的更多資訊,請參閱 產品文件。
5.4.2. 配置 Apache Geode CacheServer
Spring Data for Apache Geode 包含對配置 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/geode"
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/geode https://www.springframework.org/schema/geode/spring-geode.xsd
">
<gfe:cache/>
<!-- Example depicting serveral Apache Geode 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 和 環境抽象 來支援從主程式碼庫中外部化環境特定的屬性,從而簡化跨多個機器的部署。
|
為了避免初始化問題,Spring Data for Apache Geode 啟動的 CacheServer 在 Spring 容器完全初始化 **之後** 啟動。這樣做可以讓在宣告式定義的潛在區域、監聽器、寫入器或例項化器在伺服器開始接受連線之前完全初始化和註冊。在以程式設計方式配置這些元素時請記住這一點,因為伺服器可能會在您的元件之前啟動,因此客戶端可能無法立即看到它們。
|
5.4.3. 配置 Apache Geode 客戶端快取
除了定義 Apache Geode 對等 Cache
之外,Spring Data for Apache Geode 還支援在 Spring 容器中定義 Apache Geode ClientCache
。ClientCache
定義在配置和使用方面類似於 Apache Geode 對等 Cache,並由 org.springframework.data.gemfire.client.ClientCacheFactoryBean
支援。
使用預設配置定義 Apache Geode 快取客戶端的最簡單方法如下
<beans>
<gfe:client-cache/>
</beans>
client-cache
支援許多與 Cache 元素相同的選項。但是,與完整的對等 Cache
成員不同,快取客戶端透過 Pool 連線到遠端快取伺服器。預設情況下,將建立一個 Pool 來連線到執行在 localhost
上並監聽埠 40404
的伺服器。所有客戶端 Region 都使用預設 Pool,除非 Region 配置為使用特定 Pool。
可以使用 pool
元素定義 Pool。此客戶端池可用於直接配置與伺服器的連線,以用於單個實體或透過一個或多個 Locator 用於整個快取。
例如,要自定義 client-cache
使用的預設 Pool,開發人員需要定義一個 Pool 並將其連線到快取定義,如下面的示例所示
<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()
的呼叫。
客戶端 Region 更詳細地介紹了客戶端配置。
Apache Geode 的 DEFAULT 池和 Spring Data for Apache Geode 池定義
如果 Apache Geode ClientCache
僅限本地,則不需要池定義。例如,您可以定義以下內容
<gfe:client-cache/>
<gfe:client-region id="Example" shortcut="LOCAL"/>
在這種情況下,“Example” Region 為 LOCAL
,並且客戶端和伺服器之間沒有資料分發。因此,不需要池。對於任何客戶端側、僅限本地的 Region,情況都是如此,如 Apache Geode 的 ClientRegionShortcut
(所有 LOCAL_*
快捷方式)所定義。
但是,如果客戶端 Region 是伺服器端 Region 的(快取)代理,則需要池。在這種情況下,有幾種方法可以定義和使用池。
當 ClientCache
、池和基於代理的 Region 都已定義但未明確標識時,Spring Data for Apache Geode 會自動解析引用,如下面的示例所示
<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
,客戶端 Region 被標識為“Example”。但是,ClientCache
從 gemfirePool
初始化 Apache Geode 的 DEFAULT
池,並且客戶端 Region 在客戶端和伺服器之間分發資料時使用 gemfirePool
。
基本上,Spring Data for Apache Geode 將前面的配置解析為以下內容
<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"/>
Apache Geode 仍然會建立一個名為 DEFAULT
的池。Spring Data for Apache Geode 會導致 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"/>
在此設定中,Apache Geode client-cache
DEFAULT
池從 locatorPool
初始化,如 pool-name
屬性指定的那樣。由於兩個池都被明確標識(命名)——分別為 locatorPool
和 serverPool
,因此沒有 Spring Data for Apache Geode 定義的 gemfirePool
。
“Example” 區域明確引用並專門使用 serverPool
。AnotherExample
區域使用 Apache Geode 的 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
介面連線到需要它的應用程式類,因此實際的區域型別與程式設計模型分離。通常,每個區域都與一個域物件相關聯,類似於關係資料庫中的表。
Apache Geode 實現以下型別的區域
-
REPLICATE - 資料在定義區域的叢集中所有快取成員之間複製。這提供了非常高的讀取效能,但寫入需要更長時間來執行復制。
-
PARTITION - 資料在定義區域的叢集中許多快取成員之間劃分為桶(分片)。這提供了高讀取和寫入效能,適用於單個節點無法容納的大型資料集。
-
LOCAL - 資料僅存在於本地節點上。
-
Client - 從技術上講,客戶端區域是一個 LOCAL 區域,充當託管在叢集中快取伺服器上的 REPLICATE 或 PARTITION 區域的代理。它可能儲存本地建立或獲取的資料。或者,它可以為空。本地更新與快取伺服器同步。此外,客戶端區域可以訂閱事件,以便與訪問同一伺服器區域的遠端程序發起的更改保持同步(同步)。
有關各種區域型別及其功能以及配置選項的更多資訊,請參閱 Apache Geode 關於 區域型別 的文件。
5.5.1. 使用外部配置的區域
要引用已在 Apache Geode 本機 cache.xml
檔案中配置的區域,請使用 lookup-region
元素。只需使用 name
屬性宣告目標區域名稱。例如,要宣告一個標識為 ordersRegion
的 bean 定義,用於名為 Orders
的現有區域,可以使用以下 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. 自動區域查詢
auto-region-lookup
允許您在 <gfe:cache>
元素上使用 cache-xml-location
屬性時,將 Apache Geode 本機 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/>
Spring Data for Apache Geode 會自動為 cache.xml
中定義的所有 Apache Geode 區域建立 bean,這些區域尚未透過顯式 <gfe:lookup-region>
bean 宣告顯式新增到 Spring 容器中。
重要的是要意識到,Spring Data for Apache Geode 使用 Spring BeanPostProcessor 在快取建立和初始化後對其進行後處理,以確定在 Apache Geode 中定義的區域,以將其作為 bean 新增到 Spring ApplicationContext
中。
您可以像注入任何其他在 Spring ApplicationContext
中定義的 bean 一樣注入這些“自動查詢”的 Region,只有一個例外:您可能需要定義一個與“gemfireCache” bean 的 depends-on
關聯,如下所示
package example;
@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"/>
這樣做可以確保 Apache Geode 快取和在 cache.xml
中定義的所有 Region 在使用 <gfe:auto-region-lookup>
元素時,在任何具有自動連線引用的元件之前建立。
5.5.3. 配置 Region
Spring Data for Apache Geode 透過以下元素為配置任何型別的 Region 提供全面支援
-
LOCAL Region:
<local-region>
-
PARTITION Region:
<partitioned-region>
-
REPLICATE Region:
<replicated-region>
-
Client Region:
<client-region>
有關 Region 型別 的全面描述,請參閱 Apache Geode 文件。
通用 Region 屬性
下表列出了所有 Region 型別可用的屬性
名稱 | 值 | 描述 |
---|---|---|
cache-ref |
Apache Geode 快取 bean 引用 |
定義 Apache Geode 快取的 bean 的名稱(預設情況下為“gemfireCache”)。 |
cloning-enabled |
布林值(預設: |
當為 |
close |
布林值(預設: |
確定是否應在關閉時關閉區域。 |
concurrency-checks-enabled |
布林值(預設: |
確定成員是否執行檢查以提供對分散式區域的併發或亂序更新的一致處理。 |
data-policy |
請參閱 Apache Geode 的 資料策略。 |
區域的資料策略。請注意,並非所有資料策略都支援每種 Region 型別。 |
destroy |
布林值(預設: |
確定在關閉時是否應銷燬區域。 |
disk-store-ref |
已配置磁碟儲存的名稱。 |
對透過 |
disk-synchronous |
布林值(預設: |
確定磁碟儲存寫入是否同步。 |
id |
任何有效的 bean 名稱。 |
如果未指定 |
ignore-if-exists |
布林值(預設: |
如果區域已存在於快取中,則忽略此 bean 定義,從而導致查詢而不是建立。 |
ignore-jta |
布林值(預設: |
確定此區域是否參與 JTA(Java 事務 API)事務。 |
index-update-type |
|
確定在條目建立時是否同步或非同步更新索引。 |
initial-capacity |
整數(預設:16) |
區域條目的數量的初始記憶體分配。 |
key-constraint |
任何有效的完全限定 Java 類名。 |
預期的鍵型別。 |
load-factor |
浮點數(預設:.75) |
設定用於儲存區域條目的底層 |
name |
任何有效的區域名稱。 |
區域的名稱。如果未指定,則假定為 |
persistent |
*布林值(預設: |
確定區域是否將條目持久儲存到本地磁碟(磁碟儲存)。 |
shortcut |
參見https://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/RegionShortcut.html |
此區域的 |
statistics |
布林值(預設: |
確定區域是否報告統計資訊。 |
template |
區域模板的名稱。 |
對透過 |
value-constraint |
任何有效的完全限定 Java 類名。 |
預期的值型別。 |
CacheListener
例項
CacheListener
例項註冊到區域以處理區域事件,例如建立、更新、銷燬條目等。CacheListener
可以是實現CacheListener
介面的任何 bean。區域可以有多個偵聽器,這些偵聽器透過包含在包含*-region
元素中的cache-listener
元素中宣告。
以下示例有兩個宣告的CacheListener
。第一個引用命名、頂級 Spring bean。第二個是匿名內部 bean 定義。
<bean id="myListener" class="org.example.app.geode.cache.SimpleCacheListener"/>
<gfe:replicated-region id="regionWithListeners">
<gfe:cache-listener>
<!-- nested CacheListener bean reference -->
<ref bean="myListener"/>
<!-- nested CacheListener bean definition -->
<bean class="org.example.app.geode.cache.AnotherSimpleCacheListener"/>
</gfe:cache-listener>
</gfe:replicated-region>
以下示例使用帶有ref
屬性的cache-listener
元素的另一種形式。這樣做允許在定義單個CacheListener
時進行更簡潔的配置。
注意:XML 名稱空間只允許一個cache-listener
元素,因此必須使用前面示例中顯示的樣式或以下示例中的樣式。
<beans>
<gfe:replicated-region id="exampleReplicateRegionWithCacheListener">
<gfe:cache-listener ref="myListener"/>
</gfe:replicated-region>
<bean id="myListener" class="example.CacheListener"/>
</beans>
在cache-listener 元素中使用ref 和巢狀宣告是非法的。這兩個選項是互斥的,在同一個元素中使用兩者會導致異常。
|
Bean 引用約定
|
CacheLoaders 和 CacheWriters
與cache-listener
類似,XML 名稱空間提供cache-loader
和cache-writer
元素來為區域註冊這些 Apache Geode 元件。
CacheLoader
在快取未命中時被呼叫,以允許從外部資料來源(如資料庫)載入條目。CacheWriter
在建立或更新條目之前被呼叫,以允許將條目同步到外部資料來源。主要區別在於 Apache Geode 最多支援每個區域一個CacheLoader
和CacheWriter
例項。但是,可以使用任一宣告樣式。
以下示例聲明瞭一個同時具有CacheLoader
和CacheWriter
的區域
<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>
有關更多詳細資訊,請參閱 Apache Geode 文件中的CacheLoader
和CacheWriter
。
5.5.4. 壓縮
Apache Geode 區域也可以被壓縮,以減少 JVM 記憶體消耗和壓力,從而可能避免全域性 GC。當您為區域啟用壓縮時,儲存在區域記憶體中的所有值都會被壓縮,而鍵和索引保持未壓縮。新值在放入區域時被壓縮,所有值在從區域讀回時自動解壓縮。值在持久化到磁碟或透過網路傳送到其他對等成員或客戶端時不會被壓縮。
以下示例顯示了一個啟用了壓縮的區域
<beans>
<gfe:replicated-region id="exampleReplicateRegionWithCompression">
<gfe:compressor>
<bean class="org.apache.geode.compression.SnappyCompressor"/>
</gfe:compressor>
</gfe:replicated-region>
</beans>
有關區域壓縮的更多資訊,請參閱 Apache Geode 的文件。
5.5.5. 堆外記憶體
Apache Geode 區域也可以配置為將區域值儲存在堆外記憶體中,堆外記憶體是 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>
元素設定以下 Apache Geode 配置屬性來控制堆外記憶體管理的其他方面:
<gfe:cache critical-off-heap-percentage="90" eviction-off-heap-percentage"80"/>
Apache Geode 的 ResourceManager
將使用這兩個閾值(critical-off-heap-percentage
和 eviction-off-heap-percentage
)更有效地管理堆外記憶體,就像 JVM 管理堆記憶體一樣。Apache Geode ResourceManager
將透過逐出舊資料來防止快取消耗過多的堆外記憶體。如果堆外記憶體管理器無法跟上,那麼 ResourceManager
會拒絕向快取新增內容,直到堆外記憶體管理器釋放了足夠的記憶體。
有關 管理堆記憶體和堆外記憶體 的更多資訊,請參閱 Apache Geode 文件。
具體來說,請閱讀 管理堆外記憶體 部分。
5.5.6. 子區域
Spring Data for Apache Geode 還支援子區域,允許區域以層次結構關係排列。
例如,Apache Geode 允許使用 /Customer/Address
區域和不同的 /Employee/Address
區域。此外,子區域可以有自己的子區域和配置。子區域不會從其父區域繼承屬性。區域型別可以根據 Apache Geode 約束進行混合和匹配。子區域自然地宣告為區域的子元素。子區域的 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 Apache Geode 也支援區域模板。
此功能允許開發人員定義通用的區域配置和屬性,並在 Spring ApplicationContext
中宣告的多個區域 Bean 定義中重用該配置。
Spring Data for Apache Geode 在其名稱空間中包含五個區域模板標籤
標籤名稱 | 描述 |
---|---|
|
定義通用的區域屬性。擴充套件 XML 名稱空間中的 |
|
定義通用的“本地”區域屬性。擴充套件 XML 名稱空間中的 |
|
定義通用的“分割槽”區域屬性。擴充套件 XML 名稱空間中的 |
|
定義通用的“複製”區域屬性。擴充套件 XML 名稱空間中的 |
|
定義通用的“客戶端”區域屬性。擴充套件 XML 名稱空間中的 |
除了標籤之外,具體的 <gfe:*-region>
元素(以及抽象的 <gfe:*-region-template>
元素)具有一個 template
屬性,用於定義區域從其繼承配置的區域模板。區域模板甚至可以從其他區域模板繼承。
以下示例顯示了一種可能的配置
<beans>
<gfe:async-event-queue id="AEQ" persistent="false" parallel="false" dispatcher-threads="4">
<gfe:async-event-listener>
<bean class="example.AeqListener"/>
</gfe:async-event-listener>
</gfe:async-event-queue>
<gfe:region-template id="BaseRegionTemplate" initial-capacity="51" load-factor="0.85" persistent="false" statistics="true"
key-constraint="java.lang.Long" value-constraint="java.lang.String">
<gfe:cache-listener>
<bean class="example.CacheListenerOne"/>
<bean class="example.CacheListenerTwo"/>
</gfe:cache-listener>
<gfe:entry-ttl timeout="600" action="DESTROY"/>
<gfe:entry-tti timeout="300 action="INVLIDATE"/>
</gfe:region-template>
<gfe:region-template id="ExtendedRegionTemplate" template="BaseRegionTemplate" load-factor="0.55">
<gfe:cache-loader>
<bean class="example.CacheLoader"/>
</gfe:cache-loader>
<gfe:cache-writer>
<bean class="example.CacheWriter"/>
</gfe:cache-writer>
<gfe:async-event-queue-ref bean="AEQ"/>
</gfe:region-template>
<gfe:partitioned-region-template id="PartitionRegionTemplate" template="ExtendedRegionTemplate"
copies="1" load-factor="0.70" local-max-memory="1024" total-max-memory="16384" value-constraint="java.lang.Object">
<gfe:partition-resolver>
<bean class="example.PartitionResolver"/>
</gfe:partition-resolver>
<gfe:eviction type="ENTRY_COUNT" threshold="8192000" action="OVERFLOW_TO_DISK"/>
</gfe:partitioned-region-template>
<gfe:partitioned-region id="TemplateBasedPartitionRegion" template="PartitionRegionTemplate"
copies="2" local-max-memory="8192" persistent="true" total-buckets="91"/>
</beans>
區域模板也適用於子區域。請注意,“TemplateBasedPartitionRegion” 擴充套件了“PartitionRegionTemplate”,後者擴充套件了“ExtendedRegionTemplate”,後者擴充套件了“BaseRegionTemplate”。在後續繼承的區域 Bean 定義中定義的屬性和子元素會覆蓋父元素中的內容。
模板工作原理
Spring Data for Apache Geode 在解析 Spring ApplicationContext
配置元資料時應用區域模板,因此,必須按繼承順序宣告區域模板。換句話說,父模板必須在子模板之前定義。這樣做可以確保應用正確的配置,尤其是在元素屬性或子元素被覆蓋時。
同樣重要的是要記住,區域型別只能從其他類似型別的區域繼承。例如,<gfe:replicated-region> 無法從 <gfe:partitioned-region-template> 繼承。
|
區域模板是單繼承的。 |
關於區域、子區域和查詢的注意事項
以前,在 Spring Data for Apache Geode XML 名稱空間中,replicated-region
、partitioned-region
、local-region
和 client-region
元素的底層屬性之一是在嘗試建立區域之前先執行查詢。這樣做是為了防止區域已經存在的情況,這種情況可能發生在區域是在匯入的 Apache Geode 原生 cache.xml
配置檔案中定義的情況下。因此,首先執行查詢以避免任何錯誤。這是設計使然,可能會發生變化。
此行為已更改,預設行為現在是先建立區域。如果區域已存在,則建立邏輯會快速失敗並丟擲相應的異常。但是,與 CREATE TABLE IF NOT EXISTS …
DDL 語法類似,Spring Data for Apache Geode <gfe:*-region>
XML 名稱空間元素現在包含一個 ignore-if-exists
屬性,該屬性透過首先查詢由名稱標識的現有區域來恢復舊行為,然後再嘗試建立區域。如果透過名稱找到了現有區域,並且 ignore-if-exists
設定為 true
,則在 Spring 配置中定義的區域 bean 定義將被忽略。
Spring 團隊強烈建議僅將 replicated-region 、partitioned-region 、local-region 和 client-region XML 名稱空間元素用於定義新區域。當這些元素定義的區域已存在並且區域元素首先執行查詢時,可能會出現的一個問題是,如果您在應用程式配置中為驅逐、過期、訂閱等定義了不同的區域語義和行為,那麼區域定義可能不匹配,並且可能表現出與應用程式所需的相反行為。更糟糕的是,您可能希望將區域定義為分散式區域(例如,PARTITION ),而實際上,現有的區域定義僅是本地的。
|
推薦做法 - 僅使用 replicated-region 、partitioned-region 、local-region 和 client-region XML 名稱空間元素來定義新區域。
|
請考慮以下原生 Apache Geode 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/geode"
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/geode https://www.springframework.org/schema/geode/spring-geode.xsd
">
<gfe:cache cache-xml-location="classpath:cache.xml"/>
<gfe:lookup-region name="Customers/Accounts"/>
<gfe:lookup-region name="Customers/Accounts/Orders"/>
</beans>
Customers/Accounts
和 Customers/Accounts/Orders
區域在 Spring 容器中分別被引用為 Customers/Accounts
和 Customers/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。因此,您不應按前面兩個示例所示配置區域。
Apache Geode 在引用父區域和子區域時很靈活,無論是否使用前導斜槓。例如,父區域可以引用為 /Customers
或 Customers
,子區域可以引用為 /Customers/Accounts
或 Customers/Accounts
。但是,Spring Data for Apache Geode 在將 Bean 命名為區域時非常具體。它始終使用正斜槓 (/) 來表示子區域(例如,/Customers/Accounts
)。
因此,您應該使用前面顯示的非巢狀 lookup-region
語法,或使用前導斜槓 (/) 定義直接引用,如下所示
<gfe:lookup-region name="/Customers/Accounts"/>
<gfe:lookup-region name="/Customers/Accounts/Orders"/>
前面的示例中,巢狀的 replicated-region
元素用於引用子區域,展示了前面提到的問題。Customers、Accounts 和 Orders 區域和子區域是否持久化?它們不是持久化的,因為區域是在本地 Apache Geode cache.xml
配置檔案中定義為 REPLICATE
,並且在快取 Bean 初始化之前(一旦 <gfe:cache>
元素被處理)就存在。
5.5.8. 資料驅逐(帶溢位)
基於各種約束,每個區域都可以擁有一個驅逐策略,用於從記憶體中驅逐資料。目前,在 Apache Geode 中,驅逐適用於最近最少使用條目(也稱為 LRU)。被驅逐的條目要麼被銷燬,要麼被分頁到磁碟(稱為“溢位到磁碟”)。
Spring Data for Apache Geode 透過使用巢狀的 eviction
元素,支援 PARTITION 區域、REPLICATE 區域以及客戶端、本地區域的所有驅逐策略(條目計數、記憶體和堆使用)。
例如,要配置一個 PARTITION 區域,如果記憶體大小超過 512 MB 就溢位到磁碟,您可以指定以下配置
<gfe:partitioned-region id="examplePartitionRegionWithEviction">
<gfe:eviction type="MEMORY_SIZE" threshold="512" action="OVERFLOW_TO_DISK"/>
</gfe:partitioned-region>
副本不能使用 local destroy 驅逐,因為這會導致它們失效。有關更多資訊,請參閱 Apache Geode 文件。
|
在為溢位配置區域時,您應該透過 disk-store
元素配置儲存,以獲得最大的效率。
有關驅逐策略的詳細說明,請參閱 Apache Geode 文件中的 驅逐 部分。
5.5.9. 資料過期
Apache Geode 允許您控制條目在快取中存在的時間。過期由經過的時間驅動,而驅逐則由條目計數或堆或記憶體使用情況驅動。一旦條目過期,就無法再從快取中訪問它。
Apache Geode 支援以下過期型別
-
生存時間 (TTL):物件在最後一次建立或更新後可以在快取中保留的時間(以秒為單位)。對於條目,計數器在建立和放置操作時設定為零。區域計數器在區域建立時以及條目計數器重置時重置。
-
空閒超時 (TTI):物件在最後一次訪問後可以在快取中保留的時間(以秒為單位)。物件的空閒超時計數器在每次其 TTL 計數器重置時重置。此外,條目的空閒超時計數器在每次透過 get 操作或
netSearch
訪問條目時重置。區域的空閒超時計數器在每次其一個條目的空閒超時重置時重置。
這些都可以應用於區域本身或區域中的條目。Spring Data for Apache Geode 提供 <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>
有關過期策略的詳細說明,請參閱 Apache Geode 文件中的過期部分。
基於註解的資料過期
使用 Spring Data for Apache Geode,您可以在單個區域條目值(或者換句話說,直接在應用程式域物件上)定義過期策略和設定。例如,您可以像下面這樣在基於會話的應用程式域物件上定義過期策略
@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)時,它們會互相補充。
所有基於
|
Spring Data for Apache Geode 的@Expiration
註解支援是使用 Apache Geode 的CustomExpiry
介面實現的。有關更多詳細資訊,請參閱 Apache Geode 文件中的配置資料過期部分。
Spring Data for Apache Geode 的AnnotationBasedExpiration
類(和CustomExpiry
實現)負責處理 SDG @Expiration
註解,並在請求時為區域條目過期適當地應用過期策略配置。
要使用 Spring Data for Apache Geode 配置特定的 Apache Geode 區域以適當地將過期策略應用於使用基於@Expiration
的註解註釋的應用程式域物件,您必須
-
在 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。 -
(可選)使用 Spring Data for Apache Geode 的
@Expiration
註解(@Expiration
、@IdleTimeoutExpiration
或@TimeToLiveExpiration
)註釋儲存在區域中的應用程式域物件,這些物件具有過期策略和自定義設定。 -
(可選) 在某些情況下,特定應用程式域物件根本沒有使用 Spring Data for Apache Geode 的 `@Expiration` 註解進行註釋,但 Apache Geode Region 被配置為使用 SDG 的自定義 `AnnotationBasedExpiration` 類來確定儲存在 Region 中的物件的過期策略和設定,您可以透過以下步驟在 `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 Apache Geode 的 `@Expiration` 註解使用 `String` 作為屬性型別,而不是更合適的強型別,例如,`int` 用於 'timeout',而 SDG 的 `ExpirationActionType` 用於 'action'。為什麼是這樣呢?
好吧,讓我們看看 Spring Data for Apache Geode 的另一個功能,利用 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 Apache Geode 測試套件中進行了演示和測試。有關更多詳細資訊,請參閱 原始碼。
5.5.10. 資料持久化
區域可以是持久化的。Apache Geode 確保您放入配置為持久化的區域中的所有資料都以可恢復的方式寫入磁碟,以便您下次重新建立區域時可以恢復資料。這樣做可以讓資料在機器或程序故障後,甚至在 Apache Geode 資料節點正常關閉並隨後重新啟動後恢復。
要使用 Spring Data for Apache Geode 啟用持久化,請在任何 <*-region>
元素上將 persistent
屬性設定為 true
,如下例所示
<gfe:partitioned-region id="examplePersitentPartitionRegion" persistent="true"/>
也可以透過設定 data-policy
屬性來配置持久化。為此,請將屬性的值設定為 Apache Geode 的 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. 訂閱策略
Apache Geode 允許配置 點對點 (P2P) 事件訊息傳遞 以控制區域接收的條目事件。Spring Data for Apache Geode 提供了 <gfe:subscription/>
子元素,用於在 REPLICATE
和 PARTITION
區域上將訂閱策略設定為 ALL
或 CACHE_CONTENT
。以下示例顯示了一個區域,其訂閱策略設定為 CACHE_CONTENT
<gfe:partitioned-region id="examplePartitionRegionWithCustomSubscription">
<gfe:subscription type="CACHE_CONTENT"/>
</gfe:partitioned-region>
5.5.12. 本地區域
Spring Data for Apache Geode 提供了一個專門的 local-region
元素來建立本地區域。顧名思義,本地區域是獨立的,這意味著它們不與任何其他分散式系統成員共享資料。除此之外,所有常見的區域配置選項都適用。
以下示例顯示了一個最小宣告(同樣,該示例依賴於 Spring Data for Apache Geode XML 名稱空間命名約定來連線快取)
<gfe:local-region id="exampleLocalRegion"/>
在前面的示例中,將建立一個本地區域(如果不存在同名區域)。區域的名稱與 bean ID(exampleLocalRegion
)相同,並且該 bean 假設存在名為 gemfireCache
的 Apache Geode 快取。
5.5.13. 複製區域
REPLICATE
區域或“副本”是常見的區域型別之一。簡而言之,當區域配置為 REPLICATE
時,每個託管該區域的成員都會在本地儲存該區域條目的副本。對 REPLICATE
區域的任何更新都會分發到該區域的所有副本。當建立副本時,它會經歷一個初始化階段,在此階段它會發現其他副本並自動複製所有條目。當一個副本正在初始化時,您仍然可以繼續使用其他副本。
所有常見的配置選項都可用於 REPLICATE
區域。Spring Data for Apache Geode 提供了一個 replicated-region
元素。以下示例展示了一個最小的宣告
<gfe:replicated-region id="exampleReplica"/>
有關更多詳細資訊,請參閱 Apache Geode 的文件 分散式和複製區域。
5.5.14. 分割槽區域
Spring Data for Apache Geode XML 名稱空間也支援 PARTITION
區域。
引用 Apache Geode 文件
“分割槽區域是指資料在託管該區域的同級伺服器之間進行劃分,以便每個同級伺服器儲存資料的子集的區域。使用分割槽區域時,應用程式會看到一個邏輯檢視,該檢視看起來像一個包含區域中所有資料的單個對映。對該對映的讀或寫操作會透明地路由到託管該操作目標條目的同級伺服器。Apache Geode 將雜湊碼域劃分為桶。每個桶都分配給一個特定的同級伺服器,但可以隨時重新分配到另一個同級伺服器,以提高整個叢集的資源利用率。”
PARTITION
區域是透過使用 partitioned-region
元素建立的。它的配置選項類似於 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>
有關更多詳細資訊,請參閱 Apache Geode 的文件 分割槽區域。
分割槽區域屬性
下表提供了特定於PARTITION
區域的配置選項的快速概述。這些選項是除了前面描述的通用區域配置選項之外的。
名稱 | 值 | 描述 |
---|---|---|
副本 |
0..4 |
每個分割槽的高可用性副本數量。預設情況下,不建立副本,這意味著沒有冗餘。每個副本都提供了額外的備份,但需要額外的儲存空間。 |
與之共置 |
有效的區域名稱 |
與新建立的 |
本地最大記憶體 |
正整數 |
區域在**此**程序中使用的最大記憶體量(以兆位元組為單位)。 |
總最大記憶體 |
任何整數值 |
區域在**所有**程序中使用的最大記憶體量(以兆位元組為單位)。 |
分割槽監聽器 |
bean 名稱 |
此區域用於處理分割槽事件的 |
分割槽解析器 |
bean 名稱 |
此區域用於自定義分割槽的 |
恢復延遲 |
任何長整數值 |
現有成員在另一個成員崩潰後等待滿足冗餘的延遲(以毫秒為單位)。-1(預設值)表示在故障後不會恢復冗餘。 |
啟動恢復延遲 |
任何長整數值 |
新成員等待滿足冗餘的延遲(以毫秒為單位)。-1 表示新增新成員不會觸發冗餘恢復。預設情況下,在新增新成員時立即恢復冗餘。 |
5.5.15. 客戶端區域
Apache Geode 支援各種部署拓撲來管理和分發資料。Apache Geode 拓撲主題超出了本文件的範圍。但是,為了快速回顧,Apache Geode 支援的拓撲可以分為:點對點 (p2p)、客戶端-伺服器和廣域網 (WAN)。在最後兩種配置中,通常宣告連線到快取伺服器的客戶端區域。
Spring Data for Apache Geode 為每種配置提供了專門的支援,透過其 client-cache 元素:client-region
和 pool
。顧名思義,client-region
定義了一個客戶端 Region,而 pool
定義了一個連線池,用於各種客戶端 Region 使用和共享。
以下示例展示了一個典型的客戶端 Region 配置
<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>
與其他 Region 型別一樣,client-region
也支援 CacheListener
例項以及 CacheLoader
和 CacheWriter
。它還需要一個連線 Pool
來連線到一組 Locator 或伺服器。每個客戶端 Region 可以擁有自己的 Pool
,也可以共享同一個 Pool
。如果沒有指定 Pool
,則將使用 "DEFAULT" Pool
。
在前面的示例中,Pool 是使用 Locator 配置的。Locator 是一個獨立的程序,用於在分散式系統中發現快取伺服器和對等資料成員,建議在生產系統中使用。也可以使用 server 元素將 Pool 配置為直接連線到一個或多個快取伺服器。
|
有關在客戶端上設定選項(尤其是 Pool
上設定選項)的完整列表,請參閱 Spring Data for Apache Geode 架構(“Spring Data for Apache Geode 架構”)和 Apache Geode 的 客戶端-伺服器配置 文件。
客戶端興趣
為了最大程度地減少網路流量,每個客戶端可以單獨定義自己的“興趣”策略,指示 Apache Geode 它實際需要的資料。在 Spring Data for Apache Geode 中,可以為每個客戶端 Region 單獨定義“興趣”。支援基於鍵和基於正則表示式的興趣型別。
以下示例展示了基於鍵和基於正則表示式的 interest
型別
<gfe:client-region id="Example" pool-name="myPool">
<gfe:key-interest durable="true" result-policy="KEYS">
<bean id="key" class="java.lang.String">
<constructor-arg value="someKey"/>
</bean>
</gfe:key-interest>
<gfe:regex-interest pattern=".*" receive-values="false"/>
</gfe:client-region>
特殊鍵 ALL_KEYS
表示為所有鍵註冊“興趣”。可以使用正則表示式 ".\*"
實現相同的效果。
<gfe:*-interest>
鍵和正則表示式元素支援三個屬性:durable
、receive-values
和 result-policy
。
durable
指示當客戶端連線到叢集中的一個或多個伺服器時為客戶端建立的“興趣”策略和訂閱佇列是否在客戶端會話之間維護。如果客戶端斷開連線並重新連線,則在客戶端斷開連線時,伺服器上為客戶端維護一個 durable
訂閱佇列。當客戶端重新連線時,客戶端會收到客戶端與叢集中的伺服器斷開連線期間發生的任何事件。
對於客戶端中定義的每個已“啟用”訂閱的連線池(Pool
),叢集中的伺服器都會維護一個訂閱佇列。訂閱佇列用於儲存(並可能合併)傳送到客戶端的事件。如果訂閱佇列是持久的,它會在客戶端會話(即連線)之間持續存在,可能持續到指定的超時時間。如果客戶端在給定時間範圍內沒有返回,則會銷燬客戶端池訂閱佇列,以減少叢集中伺服器的資源消耗。如果訂閱佇列不是durable
,則在客戶端斷開連線時立即銷燬。您需要決定您的客戶端是否應該接收斷開連線期間發生的事件,或者是否只需要接收重新連線後的最新事件。
receive-values
屬性指示是否接收建立和更新事件的條目值。如果為true
,則接收值。如果為false
,則只接收失效事件。
最後,result-policy
是一個列舉,包含:KEYS
、KEYS_VALUE
和 NONE
。預設值為 KEYS_VALUES
。result-policy
控制客戶端首次連線時初始化本地快取的初始轉儲,本質上是使用與興趣策略匹配的所有條目的事件來為客戶端播種。
正如前面提到的,如果沒有在Pool
上啟用訂閱,客戶端側的興趣註冊不會有什麼作用。事實上,在沒有啟用訂閱的情況下嘗試興趣註冊是錯誤的。以下示例展示瞭如何進行操作。
<gfe:pool ... subscription-enabled="true">
...
</gfe:pool>
除了subscription-enabled
,您還可以設定subscription-ack-interval
、subscription-message-tracking-timeout
和 subscription-redundancy
。subscription-redundancy
用於控制叢集中的伺服器應該維護多少個訂閱佇列副本。如果冗餘度大於 1,並且“主”訂閱佇列(即伺服器)出現故障,那麼“備用”訂閱佇列將接管,從而防止客戶端在 HA 場景中丟失事件。
除了Pool
設定之外,伺服器端的區域使用一個額外的屬性enable-subscription-conflation
來控制傳送到客戶端的事件的合併。這也有助於進一步減少網路流量,並且在應用程式只關心條目的最新值的情況下非常有用。但是,當應用程式保留髮生的事件的時間序列時,合併會阻礙這種用例。預設值為false
。以下示例展示了伺服器上的區域配置,客戶端包含一個對應的客戶端[CACHING_]PROXY
區域,該區域對該伺服器區域中的鍵感興趣。
<gfe:partitioned-region name="ServerSideRegion" enable-subscription-conflation="true">
...
</gfe:partitioned-region>
要控制在客戶端與叢集中的伺服器斷開連線後,“持久”訂閱佇列維護的時間量(以秒為單位),請在<gfe:client-cache>
元素上設定durable-client-timeout
屬性,如下所示
<gfe:client-cache durable-client-timeout="600">
...
</gfe:client-cache>
關於客戶端興趣的工作原理和功能的完整深入討論超出了本文件的範圍。
有關更多詳細資訊,請參閱 Apache Geode 的文件,網址為 客戶端到伺服器事件分發。
5.5.16. JSON 支援
Apache Geode 支援在區域中快取 JSON 文件,以及使用 Apache Geode OQL(物件查詢語言)查詢儲存的 JSON 文件的能力。JSON 文件在內部儲存為 PdxInstance 型別,透過使用 JSONFormatter 類來執行與 JSON 文件(作為String
)之間的轉換。
Spring Data for Apache Geode 提供了<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
。
某些區域操作(特別是那些使用 Apache Geode 專有的Region.Entry 的操作,例如:entries(boolean) 、entrySet(boolean) 和getEntry() 型別)不是 AOP 建議的目標。此外,entrySet() 方法(它返回一個Set<java.util.Map.Entry<?, ?>> )也不受影響。
|
以下示例配置展示瞭如何設定pretty-print
和convert-returned-collections
屬性
<gfe-data:json-region-autoproxy region-refs="myJsonRegion" pretty-print="true" convert-returned-collections="false"/>
此功能也與GemfireTemplate
操作無縫銜接,前提是模板被宣告為 Spring bean。目前,原生QueryService
操作不支援。
5.6. 配置索引
Apache Geode 允許在 Region 資料上建立索引(有時也稱為索引),以提高 OQL(物件查詢語言)查詢的效能。
在 Spring Data for Apache Geode 中,索引使用index
元素宣告,如下例所示
<gfe:index id="myIndex" expression="someField" from="/SomeRegion" type="HASH"/>
在 Spring Data for Apache Geode 的 XML 模式(也稱為 SDG XML 名稱空間)中,index
bean 宣告不像 Apache Geode 的原生cache.xml
那樣繫結到 Region。相反,它們是類似於<gfe:cache>
元素的頂級元素。這使您可以在任何 Region 上宣告任意數量的索引,無論它們是新建立的還是已經存在的——這比 Apache Geode 的原生cache.xml
格式有了很大的改進。
Index
必須有一個名稱。您可以使用name
屬性為Index
指定一個顯式名稱。否則,index
bean 定義的 bean 名稱(即id
屬性的值)將用作Index
名稱。
expression
和from
子句構成了Index
的主要組成部分,它們標識要索引的資料(即from
子句中標識的 Region),以及用於索引資料的標準(即expression
)。expression
應該基於應用程式定義的 OQL 查詢謂詞中使用的應用程式域物件欄位,這些查詢用於查詢和查詢儲存在 Region 中的物件。
考慮以下示例,它具有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
子句必須引用一個有效的現有 Region,它是Index
如何應用於 Region 的方式。這並非 Spring Data for Apache Geode 特有的。它是 Apache Geode 的一項功能。
Index
的 type
屬性可以是 Spring Data for Apache Geode 為 IndexType
列舉定義的三個列舉值之一:FUNCTIONAL
、HASH
和 PRIMARY_KEY
。
每個列舉值對應於 QueryService
的 create[|Key|Hash]Index
方法,這些方法在實際建立(或“定義” - 您可以在下一節中找到有關“定義”索引的更多資訊)Index
時被呼叫。例如,如果 IndexType
為 PRIMARY_KEY
,則將呼叫 QueryService.createKeyIndex(..) 來建立一個 KEY
Index
。
預設值為 FUNCTIONAL
,並導致呼叫 QueryService.createIndex(..)
方法之一。有關完整選項集,請參閱 Spring Data for Apache Geode XML 架構。
有關 Apache Geode 中索引的更多資訊,請參閱 Apache Geode 使用者指南中的“使用索引”。
5.6.1. 定義索引
除了在 Spring 容器初始化時,Spring Data for Apache Geode 處理 Index
bean 定義時預先建立索引外,您還可以使用 define
屬性在建立索引之前定義所有應用程式索引,如下所示
<gfe:index id="myDefinedIndex" expression="someField" from="/SomeRegion" define="true"/>
當 define
設定為 true
(預設值為 false
)時,它不會立即建立 Index
。所有“已定義”的索引將在 Spring ApplicationContext
“重新整理”時(或者換句話說,當 Spring 容器釋出 ContextRefreshedEvent
時)一次性建立。Spring Data for Apache Geode 將自己註冊為一個 ApplicationListener
,監聽 ContextRefreshedEvent
。當觸發時,Spring Data for Apache Geode 會呼叫 QueryService.createDefinedIndexes()
.
定義索引並一次性建立它們可以提高建立索引時的速度和效率。
有關更多詳細資訊,請參閱“一次建立多個索引”。
5.6.2. IgnoreIfExists
和 Override
兩個 Spring Data for Apache Geode Index
配置選項值得特別提及:ignoreIfExists
和 override
。
這些選項分別對應於 Spring Data for Apache Geode 的 XML 名稱空間中 <gfe:index>
元素的 ignore-if-exists
和 override
屬性。
在使用這兩個選項之前,請確保您完全理解自己在做什麼。這些選項可能會影響應用程式在執行時的效能和資源(例如記憶體)消耗。因此,這兩個選項在 SDG 中預設情況下都是停用的(設定為 false )。
|
這些選項僅在 Spring Data for Apache Geode 中可用,並且存在於解決 Apache Geode 的已知限制。Apache Geode 沒有等效的選項或功能。 |
每個選項的行為都存在顯著差異,並且完全取決於丟擲的 Apache Geode Index
異常型別。這也意味著,如果未丟擲 Apache Geode Index 型別異常,則這兩個選項均無效。這些選項旨在專門處理 Apache Geode IndexExistsException
和 IndexNameConflictException
例項,這些例項可能由於各種原因(有時很模糊)而發生。這些異常有以下原因:
-
當嘗試建立
Index
時,如果存在另一個具有相同定義但名稱不同的Index
,則會丟擲IndexExistsException
。 -
當嘗試建立
Index
時,如果存在另一個具有相同名稱但定義可能不同的Index
,則會丟擲IndexNameConflictException
。
Spring Data for Apache Geode 的預設行為是始終快速失敗。因此,預設情況下不會“處理”任何 Index
異常。這些 Index
異常將包裝在 SDG GemfireIndexException
中並重新丟擲。如果您希望 Spring Data for Apache Geode 為您處理它們,可以將這兩個 Index
bean 定義選項設定為 true
。
IgnoreIfExists
始終優先於 Override
,主要是因為它使用的資源更少,因為它在兩種異常情況下都只是返回“現有”的 Index
。
IgnoreIfExists
行為
當丟擲 IndexExistsException
並且 ignoreIfExists
設定為 true
(或 <gfe:index ignore-if-exists="true">
)時,將簡單地忽略此 index
bean 定義或宣告本來要建立的 Index
,並返回現有的 Index
。
返回現有的 Index
幾乎沒有影響,因為 index
bean 定義是相同的,這是由 Apache Geode 本身決定的,而不是 SDG。
但是,這也意味著從 Apache Geode 的角度來看,您的 index
bean 定義或宣告中指定的“名稱”的 Index
實際上不存在(即,使用 QueryService.getIndexes()
)。因此,在編寫使用查詢提示的 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 ,這可以透過使用 Apache Geode API(唯一可用的方法)來查詢。
|
Override
行為
當丟擲 IndexExistsException
且 override
設定為 true
(或 <gfe:index override="true">
)時,Index
將被有效地重新命名。請記住,當存在多個具有相同定義但不同名稱的索引時,會丟擲 IndexExistsExceptions
。
Spring Data for Apache Geode 只能透過使用 Apache Geode 的 API 來實現這一點,方法是首先刪除現有 Index
,然後使用新名稱重新建立 Index
。刪除或隨後的建立呼叫都可能失敗。無法以原子方式執行這兩個操作,並在任何一個操作失敗時回滾此聯合操作。
但是,如果成功,則您將遇到與 ignoreIfExists
選項相同的問題。任何使用查詢提示並按名稱引用舊 Index
的現有 OQL 查詢語句都必須更改。
當丟擲 IndexNameConflictException
且 override
設定為 true
(或 <gfe:index override="true">
)時,現有 Index
可能被重新定義。我們說“可能”,因為當丟擲 IndexNameConflictException
時,同名現有 Index
可能具有完全相同的定義和名稱。
如果是這樣,SDG 很聰明,即使在 `override` 時也會原樣返回現有的 `Index`。這種行為沒有問題,因為名稱和定義完全相同。當然,SDG 只有在能夠找到現有的 `Index` 時才能做到這一點,這取決於 Apache Geode 的 API。如果找不到,則不會發生任何事情,並且會丟擲一個包裝了 `IndexNameConflictException` 的 SDG `GemfireIndexException`。
但是,當現有 `Index` 的定義不同時,SDG 會嘗試使用 `index` bean 定義中指定的 `Index` 定義重新建立 `Index`。請確保這是您想要的,並確保 `index` bean 定義符合您的預期和應用程式要求。
IndexNameConflictExceptions
實際上是如何發生的?
丟擲 `IndexExistsExceptions` 可能並不罕見,尤其是在使用多個配置源來配置 Apache Geode 時(Spring Data for Apache Geode、Apache Geode Cluster Config、Apache Geode 原生 `cache.xml`、API 等等)。您應該絕對優先選擇一種配置方法並堅持使用它。
但是,什麼時候會丟擲 `IndexNameConflictException` 呢?
一個特殊情況是在 `PARTITION` Region (PR) 上定義的 `Index`。當在 `PARTITION` Region (例如,`X`) 上定義 `Index` 時,Apache Geode 會將 `Index` 定義(和名稱)分發到叢集中也託管相同 `PARTITION` Region (即,“X”) 的其他對等成員。這種 `Index` 定義的分發以及對等成員隨後建立此 `Index` 是根據需要進行的(即,由託管相同 PR 的對等成員進行),並且是非同步執行的。
在此期間,Apache Geode 可能無法識別這些掛起的 PR `Index`,例如,使用 QueryService.getIndexes()
以及 QueryService.getIndexes(:Region)
,甚至使用 QueryService.getIndex(:Region, indexName:String)
。
因此,SDG 或其他 Apache Geode 快取客戶端應用程式(不涉及 Spring)唯一確定的方法是嘗試建立 `Index`。如果它因 `IndexNameConflictException` 甚至 `IndexExistsException` 而失敗,則應用程式知道存在問題。這是因為 `QueryService` `Index` 建立會等待掛起的 `Index` 定義,而其他 Apache Geode API 呼叫則不會。
無論如何,SDG 會盡力嘗試通知您發生了什麼或正在發生的事情,並告知您糾正措施。鑑於所有 Apache Geode `QueryService.createIndex(..) `方法都是同步的阻塞操作,因此在丟擲任何一種索引型別異常後,Apache Geode 的狀態應保持一致且可訪問。因此,SDG 可以根據您的配置檢查系統狀態並採取相應措施。
在所有其他情況下,SDG 採用快速失敗策略。
5.7. 配置 DiskStore
Spring Data for Apache Geode 透過 `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 閘道器的持久備份。多個 Apache Geode 元件可以共享同一個 `DiskStore`。此外,可以為單個 `DiskStore` 定義多個檔案系統目錄,如前面的示例所示。
有關 `DiskStore` 例項的永續性和溢位以及配置選項的完整說明,請參閱 Apache Geode 文件 永續性和溢位。
5.8. 配置快照服務
Spring Data for Apache Geode 透過使用 Apache Geode 的快照服務 支援快取和區域快照。開箱即用的快照服務支援提供了一些方便的功能,簡化了 Apache Geode 的 快取 和 區域 快照服務 API 的使用。
正如 Apache Geode 文件 所解釋的那樣,快照允許您儲存快取資料,並在以後重新載入,這對於在環境之間移動資料非常有用,例如從生產環境移動到暫存或測試環境,以便在受控環境中重現與資料相關的問題。您可以將 Spring Data for Apache Geode 的快照服務支援與 Spring 的 bean 定義配置檔案 相結合,根據需要載入特定於環境的快照資料。
Spring Data for Apache Geode 對 Apache Geode 的快照服務的支援從 `
例如,您可以使用幾個快照匯入和一個數據匯出定義來定義要載入和儲存的快取範圍快照,如下所示
<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 Apache Geode 應用程式的路徑,即 JVM 程序的工作目錄。
前面的示例非常簡單,在這種情況下定義的快照服務引用了 Apache Geode 快取例項,其預設名稱為 `gemfireCache`(如 配置快取 中所述)。如果您將快取 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 Apache Geode 的 `SnapshotServiceFactoryBean` 會將 `region-ref` 屬性值解析為 Spring 容器中定義的區域 bean,並建立一個 RegionSnapshotService
。快照匯入和匯出定義的功能相同。但是,`location` 必須引用匯出檔案。
Apache Geode 對匯入的快照檔案實際上在被引用之前就存在非常嚴格。對於匯出,Apache Geode 會建立快照檔案。如果要匯出的快照檔案已存在,則會覆蓋資料。 |
Spring Data for Apache Geode 在 ` |
5.8.1. 快照位置
使用基於快取的快照服務(即 CacheSnapshotService
),您通常會向其傳遞一個包含所有要載入的快照檔案的目錄,而不是單個快照檔案,因為 `CacheSnapshotService` API 中的過載 load
方法所指示的那樣。
當然,您可以使用過載的 `load(:File[], :SnapshotFormat, :SnapshotOptions)` 方法來指定要載入到 Apache Geode 快取中的特定快照檔案。 |
然而,Spring Data for Apache Geode 認識到,典型的開發人員工作流程可能是從一個環境中提取和匯出資料到多個快照檔案,將所有檔案壓縮成一個 zip 檔案,然後方便地將該 zip 檔案移動到另一個環境中進行匯入。
因此,Spring Data for Apache Geode 允許您在匯入基於 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 Apache Geode 方便地提取提供的 zip 檔案,並將其視為目錄匯入(載入)。
5.8.2. 快照過濾器
定義多個快照匯入和匯出真正的強大之處在於使用快照過濾器。快照過濾器實現 Apache Geode 的 SnapshotFilter
介面,用於過濾區域條目,以便在匯入時包含在區域中,並在匯出時包含在快照中。
Spring Data for Apache Geode 允許您在匯入和匯出時使用快照過濾器,方法是使用 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
類來表達更復雜的快照過濾器。此類實現了 Apache Geode 的 SnapshotFilter 介面以及 組合 軟體設計模式。
簡而言之,組合 軟體設計模式允許您組合多個相同型別的物件,並將聚合視為該物件型別的單個例項——這是一種強大而有用的抽象。
ComposableSnapshotFilter
具有兩個工廠方法,and
和 or
。它們允許您分別使用 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>
然後,您可以繼續使用 or
將 activesUsersSinceFilter
與另一個過濾器組合,如下所示
<bean id="covertOrActiveUsersSinceFilter" class="org.springframework.data.gemfire.snapshot.filter.ComposableSnapshotFilter"
factory-method="or">
<constructor-arg index="0">
<list>
<ref bean="activeUsersSinceFilter"/>
<bean class="example.gemfire.snapshot.filter.CovertUsersFilter"/>
</list>
</constructor-arg>
</bean>
5.8.3. 快照事件
預設情況下,Spring Data for Apache Geode 在啟動時使用 Apache Geode 的快照服務來匯入資料,在關閉時使用快照服務來匯出資料。但是,您可能希望在 Spring 應用程式中觸發週期性的基於事件的快照,用於匯入或匯出。
為此,Spring Data for Apache Geode 定義了兩個額外的 Spring 應用程式事件,擴充套件了 Spring 的 ApplicationEvent
類,分別用於匯入和匯出:ImportSnapshotApplicationEvent
和 ExportSnapshotApplicationEvent
。
這兩個應用程式事件可以針對整個 Apache Geode 快取或針對單個 Apache Geode 區域。這些類中的建構函式接受可選的區域路徑名(例如 /Example
)以及零個或多個 SnapshotMetadata
例項。
SnapshotMetadata
陣列會覆蓋由 <gfe-data:snapshot-import>
和 <gfe-data:snapshot-export>
子元素定義的快照元資料,這些子元素用於快照應用程式事件未明確提供 SnapshotMetadata
的情況。每個單獨的 SnapshotMetadata
例項都可以定義自己的 location
和 filters
屬性。
在 Spring ApplicationContext
中定義的所有快照服務 Bean 都接收匯入和匯出快照應用程式事件。但是,只有匹配的快照服務 Bean 處理匯入和匯出事件。
基於區域的 [Import|Export]SnapshotApplicationEvent
匹配,如果定義的快照服務 Bean 是 RegionSnapshotService
並且其區域引用(由 region-ref
屬性確定)與快照應用程式事件指定的區域路徑名匹配。
基於快取的 [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 Apache Geode 提供了 註釋 支援來實現、註冊和執行 Apache Geode 函式。
Spring Data for Apache Geode 還提供了 XML 名稱空間支援來註冊 Apache Geode 函式 以進行遠端函式執行。
有關函式執行框架的更多資訊,請參閱 Apache Geode 的 文件。
Apache Geode 函式被宣告為 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 閘道器提供了一種跨地理位置同步 Apache Geode 分散式系統的方法。Spring Data for Apache Geode 提供了 XML 名稱空間支援,用於配置 WAN 閘道器,如以下示例所示。
5.10.1. Apache Geode 7.0 中的 WAN 配置
在以下示例中,GatewaySenders
是為 PARTITION
區域配置的,方法是在區域中新增子元素(gateway-sender
和 gateway-sender-ref
)。GatewaySender
可以註冊 EventFilters
和 TransportFilters
。
以下示例還展示了 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
也可以配置 EventFilters
和 TransportFilters
,如下所示
<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>
有關所有配置選項的詳細說明,請參閱 Apache Geode 文件。
6. 使用註解將 Apache Geode 與 Spring 容器一起啟動
Spring Data for Apache Geode (SDG) 2.0 引入了一種新的基於註解的配置模型,用於使用 Spring 容器配置和啟動 Apache Geode。
在 Spring 上下文中引入基於註解的 Apache Geode 配置方法的主要動機是使 Spring 應用程式開發人員能夠快速且輕鬆地啟動和執行。
讓我們開始吧!
如果您想更快地入門,請參考 快速入門 部分。 |
6.1. 簡介
Apache Geode 以及 Spring Data for Apache Geode 提供了許多配置選項
此外,Apache Geode 和 Spring Data for Apache Geode 都支援不同的拓撲結構
所有這些配置選項和拓撲結構安排在設定和使用 Apache Geode 時可能會帶來挑戰。Spring Data for Apache Geode 基於註解的配置模型旨在簡化拓撲結構等方面的配置。
基於註解的配置模型是使用 Spring Data for Apache Geode 的 XML 名稱空間的基於 XML 的配置的替代方案。使用 XML,您可以使用 `gfe` XML 模式進行配置,並使用 `gfe-data` XML 模式進行資料訪問。有關更多詳細資訊,請參見“使用 Spring 容器引導 Apache Geode”。
從 SDG 2.0 開始,基於註解的配置模型尚不支援 Apache Geode 的 WAN 元件和拓撲結構的配置。 |
與 Spring Boot 一樣,Spring Data for Apache Geode 的基於註解的配置模型被設計為一種約定優於配置的方法,用於使用 Apache Geode。實際上,這種基於註解的配置模型的靈感來自 Spring Boot 以及其他幾個 Spring 和 Spring Data 專案。
透過遵循約定,所有註解都為所有配置屬性提供合理且明智的預設值。給定註解屬性的預設值直接對應於 Apache Geode 中為相同配置屬性提供的預設值。
目的是讓您透過在 Spring `@Configuration` 或 `@SpringBootApplication` 類上宣告相應的註解來啟用 Apache Geode 功能或嵌入式服務,而無需不必要地配置大量屬性來使用該功能或服務。
再次強調,快速入門、快速和輕鬆是主要目標。
但是,如果您需要自定義 Apache Geode 的配置元資料和行為,則可以選擇這樣做,Spring Data for Apache Geode 的基於註解的配置會默默地退後。您只需要指定要調整的配置屬性。此外,正如我們將在本文件後面看到的那樣,有幾種方法可以使用註解來配置 Apache Geode 功能或嵌入式服務。
您可以在 `org.springframework.data.gemfire.config.annotation` 包中找到所有新的 SDG Java `Annotations`。
6.2. 使用 Spring 配置 Apache Geode 應用程式
與所有以在應用程式類上使用@SpringBootApplication
註解開始的 Spring Boot 應用程式一樣,Spring Boot 應用程式可以透過宣告以下三個主要註解中的任何一個輕鬆地成為 Apache Geode 快取應用程式。
-
@ClientCacheApplication
-
@PeerCacheApplication
-
@CacheServerApplication
這三個註解是 Spring 應用程式開發人員在使用 Apache Geode 時開始工作的起點。
為了實現這些註解背後的意圖,您必須瞭解可以使用 Apache Geode 建立兩種型別的快取例項:客戶端快取或對等快取。
您可以將 Spring Boot 應用程式配置為 Apache Geode 快取客戶端,使用ClientCache
例項,該例項可以與用於管理應用程式資料的現有 Apache Geode 伺服器叢集通訊。客戶端-伺服器拓撲是使用 Apache Geode 時最常見的系統架構,您可以透過使用@ClientCacheApplication
註解您的 Spring Boot 應用程式,使其成為帶有ClientCache
例項的快取客戶端。
或者,Spring Boot 應用程式可以是 Apache Geode 叢集的對等成員。也就是說,應用程式本身只是管理資料的伺服器叢集中的另一臺伺服器。當您使用@PeerCacheApplication
註解您的應用程式類時,Spring Boot 應用程式會建立一個“嵌入式”的對等Cache
例項。
擴充套件而言,對等快取應用程式也可以充當CacheServer
,允許快取客戶端連線並對伺服器執行資料訪問操作。這可以透過在應用程式類上使用@CacheServerApplication
註解來實現,而不是使用@PeerCacheApplication
,這將建立一個對等Cache
例項以及允許快取客戶端連線的CacheServer
。
預設情況下,Apache Geode 伺服器不一定是快取伺服器。也就是說,伺服器不一定是為快取客戶端提供服務的,即使它是一個伺服器。Apache Geode 伺服器可以是叢集的成員節點(資料節點),管理資料而不為任何客戶端提供服務,而叢集中的其他成員節點確實設定為在管理資料的同時為客戶端提供服務。還可以將叢集中的某些成員節點設定為非資料節點,稱為 資料訪問器,它們不儲存資料,但充當代理以作為 CacheServers 為客戶端提供服務。Apache Geode 支援許多不同的拓撲結構和叢集安排,但不在本文件的討論範圍之內。
|
例如,如果您想建立一個 Spring Boot 快取客戶端應用程式,請從以下步驟開始
ClientCache
應用程式@SpringBootApplication
@ClientCacheApplication
class ClientApplication { .. }
或者,如果您想建立一個帶有嵌入式成員節點 Cache
例項的 Spring Boot 應用程式,其中您的應用程式將是 Apache Geode 形成的叢集(分散式系統)的伺服器和成員節點,請從以下步驟開始
Cache
應用程式@SpringBootApplication
@PeerCacheApplication
class ServerApplication { .. }
或者,您可以使用 @CacheServerApplication
註解代替 @PeerCacheApplication
來建立一個嵌入式成員節點 Cache
例項以及一個在 localhost
上執行的 CacheServer
,監聽預設的快取伺服器埠 40404
,如下所示
Cache
應用程式,帶有 CacheServer
@SpringBootApplication
@CacheServerApplication
class ServerApplication { .. }
6.3. 客戶端/伺服器應用程式詳解
客戶端可以有多種方式連線到 Apache Geode 叢集中的伺服器並與之通訊。最常見且推薦的方法是使用 Apache Geode 定位器。
快取客戶端可以連線到 Apache Geode 叢集中的一個或多個定位器,而不是直接連線到 CacheServer 。與直接連線到 CacheServer 相比,使用定位器的優勢在於定位器提供了有關客戶端連線到的叢集的元資料。這些元資料包括有關哪些伺服器包含感興趣的資料或哪些伺服器負載最小的資訊。與定位器一起使用的客戶端 Pool 還提供了故障轉移功能,以防 CacheServer 崩潰。透過在客戶端 Pool 中啟用 PARTITION 區域 (PR) 單跳功能,客戶端將直接路由到包含客戶端請求和需要的資料的伺服器。
|
定位器也是叢集中的對等成員。定位器實際上構成了 Apache Geode 節點叢集的組成部分。也就是說,所有透過定位器連線的節點都是叢集中的對等節點,新成員使用定位器加入叢集並查詢其他成員。 |
預設情況下,Apache Geode 在建立 ClientCache
例項時,會設定一個連線到在 localhost
上執行的 CacheServer
的“DEFAULT”Pool
,該 CacheServer
在埠 40404
上監聽。CacheServer
在埠 40404
上監聽,接受所有系統 NIC 上的連線。您無需執行任何特殊操作即可使用客戶端-伺服器拓撲。只需在您的伺服器端 Spring Boot 應用程式中使用 @CacheServerApplication
註解,在您的客戶端端 Spring Boot 應用程式中使用 @ClientCacheApplication
註解,您就可以開始使用了。
如果您願意,您甚至可以使用 Gfsh 的 start server
命令啟動您的伺服器。您的 Spring Boot @ClientCacheApplication
仍然可以連線到伺服器,無論它如何啟動。但是,您可能更喜歡使用 Spring Data for Apache Geode 方法配置和啟動您的伺服器,因為正確註釋的 Spring Boot 應用程式類更直觀,更容易除錯。
作為應用程式開發人員,您無疑希望自定義 Apache Geode 設定的“DEFAULT”Pool
,以可能連線到一個或多個定位器,如下面的示例所示。
ClientCache
應用程式@SpringBootApplication
@ClientCacheApplication(locators = {
@Locator(host = "boombox" port = 11235),
@Locator(host = "skullbox", port = 12480)
})
class ClientApplication { .. }
除了 locators
屬性之外,@ClientCacheApplication
註解還具有 servers
屬性。servers
屬性可用於指定一個或多個巢狀的 @Server
註解,這些註解允許快取客戶端在必要時直接連線到一個或多個伺服器。
您可以使用 locators 或 servers 屬性,但不能同時使用兩者(這是由 Apache Geode 強制執行的)。
|
您還可以使用 @EnablePool
和 @EnablePools
註解配置其他 Pool
例項(除了在使用 @ClientCacheApplication
註解建立 ClientCache
例項時由 Apache Geode 提供的“DEFAULT”Pool
之外)。
@EnablePools 是一個複合註解,它在一個類上聚合了多個巢狀的 @EnablePool 註解。Java 8 及更早版本不允許在一個類上宣告多個相同型別的註解。
|
以下示例使用@EnablePool
和@EnablePools
註解
ClientCache
應用程式,使用多個命名Pools
@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 的名稱,以及用於引用相應配置屬性的名稱。它也是 Apache Geode 註冊和使用的Pool
的名稱。
類似地,在伺服器端,您可以配置多個CacheServers
,客戶端可以連線到這些伺服器,如下所示
CacheServer
應用程式,使用多個命名CacheServers
@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. 配置和引導定位器
除了 Apache Geode 快取應用程式之外,您還可以建立 Apache Geode 定位器應用程式。
Apache Geode 定位器是一個 JVM 程序,允許節點作為對等成員加入 Apache Geode 叢集。定位器還使客戶端能夠發現叢集中的伺服器。定位器為客戶端提供元資料,以在叢集中的成員之間均勻地平衡負載,啟用單跳資料訪問操作,以及其他功能。
關於定位器的完整討論超出了本文件的範圍。鼓勵讀者閱讀 Apache Geode 使用者指南,以瞭解有關定位器及其在叢集中的作用的更多詳細資訊。
要配置和引導獨立的定位器程序,請執行以下操作
@SpringBootApplication
@LocatorApplication(port = 12345)
class LocatorApplication { ... }
您可以在叢集中啟動多個定位器。唯一的要求是成員名稱在叢集中必須是唯一的。使用@LocatorApplication
註解的name
屬性來相應地命名叢集中的成員定位器。或者,您可以在 Spring Boot 的application.properties
中設定spring.data.gemfire.locator.name
屬性。
此外,您必須確保每個定位器都在唯一的埠上啟動,如果您在同一臺機器上派生多個定位器。設定port
註解屬性或spring.data.gemfire.locator.port
屬性。
然後,您可以啟動 1 個或多個由定位器(或定位器)加入的 Apache Geode 對等快取成員,這些定位器也使用 Spring 配置和引導,如下所示
CacheServer
應用程式,由localhost
上的定位器加入,埠為12345
@SpringBootApplication
@CacheServerApplication(locators = "localhost[12345]")
class ServerApplication { ... }
同樣,您可以啟動任意數量的ServerApplication
類,這些類由我們上面的定位器加入,您只需要確保成員的名稱是唯一的。
@LocatorApplication
用於配置和引導獨立的 Apache Geode Locator 應用程式程序。此程序只能是 Locator,不能是其他任何東西。如果您嘗試使用快取例項啟動 Locator,SDG 將丟擲錯誤。
如果您想同時啟動快取例項和嵌入式 Locator,則應使用 @EnableLocator
註解。
在開發過程中啟動嵌入式 Locator 很方便。但是,強烈建議您在生產環境中執行獨立的 Locator 程序以實現高可用性。如果叢集中的所有 Locator 都停止執行,則叢集將保持完整,但是,沒有新的成員能夠加入叢集,這對於為了滿足需求而進行線性擴充套件至關重要。
有關更多詳細資訊,請參閱有關 配置嵌入式 Locator 的部分。
6.5. 使用 Configurers
進行執行時配置
在設計基於註解的配置模型時,另一個目標是在註解屬性中保留型別安全。例如,如果配置屬性可以用 int
(例如埠號)表示,則屬性的型別應為 int
。
不幸的是,這不利於在執行時進行動態和可解析的配置。
Spring 的一個更精細的功能是在 Spring 容器中配置 bean 時,能夠在配置元資料的屬性或屬性中使用屬性佔位符和 SpEL 表示式。但是,這將要求所有註解屬性都為 String
型別,從而放棄型別安全,這是不可取的。
因此,Spring Data for Apache Geode 借鑑了 Spring 中另一個常用的模式,Configurers
。Spring Web MVC 中提供了許多不同的 Configurer
介面,包括 org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer
。
Configurers
設計模式使應用程式開發人員能夠在啟動時收到回撥以自定義元件或 bean 的配置。框架回調到使用者提供的程式碼以在執行時調整配置。此模式的一個更常見的用途是根據應用程式的執行時環境提供條件配置。
Spring Data for Apache Geode 提供了幾個 Configurer
回撥介面,用於在執行時自定義基於註解的配置元資料的不同方面,在建立註解的 Spring 管理 bean 之前。
-
CacheServerConfigurer
-
ClientCacheConfigurer
-
ContinuousQueryListenerContainerConfigurer
-
DiskStoreConfigurer
-
IndexConfigurer
-
PeerCacheConfigurer
-
PoolConfigurer
-
RegionConfigurer
-
GatewayReceiverConfigurer
-
GatewaySenderConfigurer
例如,您可以使用CacheServerConfigurer
和ClientCacheConfigurer
分別自定義 Spring Boot CacheServer
和 ClientCache
應用程式使用的埠號。
考慮以下來自伺服器應用程式的示例
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 Apache Geode 提供的所有Configurers
在回撥中獲取兩部分資訊:在 Spring 容器中由註釋建立的 bean 的名稱,以及對註釋用於建立和配置 Apache Geode 元件的FactoryBean
的引用(例如,ClientCache
例項使用ClientCacheFactoryBean
建立和配置)。
SDG FactoryBeans 是 SDG 公共 API 的一部分,如果您沒有提供這種新的基於註釋的配置模型,您將在 Spring 的基於 Java 的容器配置中使用它。實際上,註釋本身正在使用這些相同的FactoryBeans 進行配置。因此,本質上,註釋是一個提供額外抽象層的門面,為了方便起見。
|
鑑於Configurer
可以像任何其他 POJO 一樣宣告為常規 bean 定義,您可以結合不同的 Spring 配置選項,例如使用帶有Conditions
的 Spring Profiles,這些Conditions
使用屬性佔位符和 SpEL 表示式。這些和其他巧妙的功能讓您建立更復雜和靈活的配置。
但是,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
類簡化為以下內容
@ClientCacheApplication
類@SpringBootApplication
@ClientCacheApplication
@EnablePools(pools = {
@EnablePool(name = "Venus"),
@EnablePool(name = "Saturn"),
@EnablePool(name = "Neptune")
})
class ClientApplication { .. }
同樣,@CacheServerApplication
類變為以下內容
@CacheServerApplication
類@SpringBootApplication
@CacheServerApplication(name = "SpringServerApplication")
@EnableCacheServers(servers = {
@EnableCacheServer(name = "Venus"),
@EnableCacheServer(name = "Saturn"),
@EnableCacheServer(name = "Neptune")
})
class ServerApplication { .. }
前面的示例說明了為什麼在某些情況下,即使是必需的,也要“命名”基於註釋的 bean。這樣做可以從 XML、屬性和 Java 中引用 Spring 容器中的 bean。甚至可以將註釋定義的 bean 注入應用程式類,無論出於何種目的,如下面的示例所示
@Component
class MyApplicationComponent {
@Resource(name = "Saturn")
CacheServer saturnCacheServer;
...
}
同樣,命名註釋定義的 bean 使您可以編寫一個Configurer
來自定義特定的“命名” bean,因為beanName
是傳遞給回撥的兩個引數之一。
通常,關聯的註釋屬性屬性採用兩種形式:一個“命名”屬性和一個“未命名”屬性。
以下示例顯示了這種安排
spring.data.gemfire.cache.server.bind-address=10.105.20.1
spring.data.gemfire.cache.server.Venus.bind-address=10.105.20.2
spring.data.gemfire.cache.server.Saturn...
spring.data.gemfire.cache.server.Neptune...
雖然上面有三個名為CacheServers
,但也存在一個未命名的CacheServer
屬性,它為該屬性的任何未指定值提供預設值,即使對於“命名”的CacheServers
也是如此。因此,雖然“Venus”設定並覆蓋了自己的bind-address
,但“Saturn”和“Neptune”繼承自“未命名”的spring.data.gemfire.cache.server.bind-address
屬性。
請參閱註釋的 Javadoc,瞭解哪些註釋屬性支援基於屬性的配置,以及它們是否支援“命名”屬性而不是預設的“未命名”屬性。
6.6.1. Properties
of Properties
以通常的 Spring 方式,您甚至可以根據其他Properties
來表達Properties
,無論是透過以下示例顯示了在application.properties
檔案中設定巢狀屬性
spring.data.gemfire.cache.server.port=${gemfire.cache.server.port:40404}
以下示例顯示了在 Java 中設定巢狀屬性
@Bean
CacheServerConfigurer cacheServerPortConfigurer(
@Value("${gemfire.cache.server.port:${some.other.property:40404}}")
int cacheServerPort) {
...
}
屬性佔位符巢狀可以任意深度。 |
6.7. 配置嵌入式服務
Apache Geode 提供了啟動許多不同嵌入式服務的能力,這些服務根據用例需要由應用程式使用。
6.7.1. 配置嵌入式定位器
如前所述,Apache Geode 定位器由客戶端用於連線到叢集並查詢叢集中的伺服器。此外,加入現有叢集的新成員使用定位器來查詢其對等節點。
對於應用程式開發人員來說,在開發他們的 Spring Boot 和 Spring Data for Apache Geode 應用程式時,啟動一個由兩個或三個 Apache Geode 伺服器組成的小型叢集通常很方便。與其啟動一個單獨的定位器程序,不如使用 @EnableLocator
註解您的 Spring Boot @CacheServerApplication
類,如下所示
CacheServer
應用程式執行嵌入式定位器@SpringBootApplication
@CacheServerApplication
@EnableLocator
class ServerApplication { .. }
@EnableLocator
註解在執行在 localhost
上的 Spring Apache Geode CacheServer
應用程式中啟動一個嵌入式定位器,監聽預設的定位器埠 10334
。您可以使用相應的註解屬性自定義嵌入式定位器繫結的 host
(繫結地址)和 port
。
或者,您可以透過在 application.properties
中設定相應的 spring.data.gemfire.locator.host
和 spring.data.gemfire.locator.port
屬性來設定 @EnableLocator
屬性。
然後,您可以透過連線到此定位器來啟動其他啟用了 Spring Boot @CacheServerApplication
的應用程式,如下所示
CacheServer
應用程式連線到定位器@SpringBootApplication
@CacheServerApplication(locators = "localhost[10334]")
class ServerApplication { .. }
您甚至可以將前面顯示的兩個應用程式類組合成一個類,並使用您的 IDE 建立不同的執行配置檔案配置,以使用 Java 系統屬性啟動同一類的不同例項,這些例項具有略微修改的配置,如下所示
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 { }
}
然後,對於每個執行配置檔案,您可以設定和更改以下系統屬性
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
,並在本地系統上執行一個小型 Apache Geode 伺服器叢集(分散式系統)。
@EnableLocator 註解旨在僅用作開發時註解,而不是應用程式開發人員在生產中使用的註解。我們強烈建議將定位器作為獨立的獨立程序在叢集中執行。
|
有關 Apache Geode 定位器工作原理的更多詳細資訊,請參見此處。
6.7.2. 配置嵌入式管理器
Apache Geode 管理器是叢集中的另一個對等成員或節點,負責叢集“管理”。管理包括建立Regions
、Indexes
、DiskStores
等,以及監控叢集元件的執行時操作和行為。
管理器允許啟用 JMX 的客戶端(例如Gfsh shell 工具)連線到管理器以管理叢集。還可以使用 JDK 提供的工具(例如 JConsole 或 JVisualVM)連線到管理器,因為它們都是啟用 JMX 的客戶端。
您可能還想將前面顯示的 Spring @CacheServerApplication
啟用為管理器。為此,請使用@EnableManager
註解您的 Spring @Configuration
或 @SpringBootApplication
類。
預設情況下,管理器繫結到localhost
,在預設管理器埠1099
上監聽。管理器的幾個方面可以透過註解屬性或相應的屬性進行配置。
以下示例展示瞭如何在 Java 中建立嵌入式管理器
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 客戶端連線並找到叢集中的管理器。如果不存在,定位器將承擔管理器的角色。但是,如果不存在定位器,我們需要使用以下方法直接連線到管理器
connect
命令直接連線到管理器gfsh>connect --jmx-manager=localhost[1099]
與@EnableLocator 註解一樣,@EnableManager 註解也旨在僅用作開發時註解,而不是應用程式開發人員在生產中使用的註解。我們強烈建議管理器(如定位器)在叢集中作為獨立的、獨立的和專用的程序。
|
有關 Apache Geode 管理和監控的更多詳細資訊,請訪問 此處。
6.7.3. 配置嵌入式 HTTP 伺服器
Apache Geode 還能夠執行嵌入式 HTTP 伺服器。當前實現由 Eclipse Jetty 支援。
嵌入式 HTTP 伺服器用於託管 Apache Geode 的管理(Admin)REST API(不是公開宣傳的 API)、開發者 REST API 和 Pulse 監控 Web 應用程式。
但是,要使用任何這些 Apache Geode 提供的 Web 應用程式,您必須在系統上安裝完整的 Apache Geode 安裝程式,並且必須將 GEODE_HOME
環境變數設定為您的安裝目錄。
要啟用嵌入式 HTTP 伺服器,請將 @EnableHttpService
註解新增到任何 @PeerCacheApplication
或 @CacheServerApplication
註解類,如下所示
CacheServer
應用程式@SpringBootApplication
@CacheServerApplication
@EnableHttpService
public class ServerApplication { .. }
預設情況下,嵌入式 HTTP 伺服器在埠 7070
上監聽 HTTP 客戶端請求。當然,您可以使用註解屬性或相應的配置屬性根據需要調整埠。
請參閱前面的連結以獲取有關 HTTP 支援和提供的服務的更多詳細資訊。
6.7.4. 配置嵌入式 Memcached 伺服器(Gemcached)
Apache Geode 還實現了 Memcached 協議,並能夠為 Memcached 客戶端提供服務。也就是說,Memcached 客戶端可以連線到 Apache Geode 叢集並執行 Memcached 操作,就好像叢集中的 Apache Geode 伺服器是實際的 Memcached 伺服器一樣。
要啟用嵌入式 Memcached 服務,請將 @EnableMemcachedServer
註解新增到任何 @PeerCacheApplication
或 @CacheServerApplication
註解類,如下所示
CacheServer
應用程式@SpringBootApplication
@CacheServerApplication
@EnabledMemcachedServer
public class ServerApplication { .. }
有關 Apache Geode 的 Memcached 服務(稱為“Gemcached”)的更多詳細資訊,請訪問 此處。
6.7.5. 配置嵌入式 Redis 伺服器
Apache Geode 也實現了 Redis 伺服器協議,這使得 Redis 客戶端能夠連線到 Apache Geode 伺服器叢集並與之通訊以發出 Redis 命令。截至撰寫本文時,Apache Geode 中的 Redis 伺服器協議支援仍處於實驗階段。
要啟用嵌入式 Redis 服務,請將 @EnableRedisServer
註解新增到任何 @PeerCacheApplication
或 @CacheServerApplication
註解的類中,如下所示
CacheServer
應用程式@SpringBootApplication
@CacheServerApplication
@EnableRedisServer
public class ServerApplication { .. }
您必須在 Spring [Boot] 應用程式類路徑上顯式宣告 org.apache.geode:geode-redis 模組。
|
有關 Apache Geode Redis 介面卡的更多詳細資訊,請參閱 此處。
6.8. 配置日誌記錄
通常,有必要提高日誌記錄級別以準確瞭解 Apache Geode 的執行情況和時間。
要啟用日誌記錄,請使用 @EnableLogging
註解您的應用程式類,並設定適當的屬性或關聯的屬性,如下所示
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. 配置統計資訊
為了更深入地瞭解 Apache Geode 的執行時情況,您可以啟用統計資訊。收集統計資料有助於在發生複雜問題時進行系統分析和故障排除,這些問題通常是分散式的,並且時間是一個關鍵因素。
啟用統計資訊後,您可以使用 Apache Geode 的 VSD(視覺化統計資訊顯示) 工具來分析收集的統計資料。
要啟用統計資訊,請使用 @EnableStatistics
註解您的應用程式類,如下所示
ClientCache
應用程式@SpringBootApplication
@ClientCacheApplication
@EnableStatistics
public class ClientApplication { .. }
在伺服器上啟用統計資訊在評估效能時特別有價值。為此,請使用 @EnableStatistics
註解您的 @PeerCacheApplication
或 @CacheServerApplication
類。
您可以使用 @EnableStatistics
註解屬性或關聯屬性來自定義統計資訊收集和收集過程。
有關更多詳細資訊,請參閱 @EnableStatistics
註解 Javadoc。
有關 Apache Geode 統計資訊的更多詳細資訊,請參閱 此處。
6.10. 配置 PDX
Apache Geode 的一項更強大的功能是 PDX 序列化。雖然本文件無法全面討論 PDX,但使用 PDX 進行序列化是 Java 序列化的更好替代方案,具有以下優點
-
PDX 使用集中式型別登錄檔來使物件的序列化位元組更緊湊。
-
PDX 是一種中立的序列化格式,允許 Java 和 Native 客戶端在同一資料集上操作。
-
PDX 支援版本控制,並允許在不影響使用舊版或新版 PDX 序列化物件的現有應用程式的情況下新增或刪除物件欄位,而不會丟失資料。
-
PDX 允許在 OQL 查詢投影和謂詞中單獨訪問物件欄位,而無需先反序列化物件。
一般來說,在 Apache Geode 中,任何時候資料在客戶端和伺服器之間傳輸,或者在叢集中的對等節點之間傳輸,或者在正常分佈和複製過程中,以及當資料溢位或持久化到磁碟時,都需要進行序列化。
啟用 PDX 序列化比修改所有應用程式域物件型別以實現 java.io.Serializable
更加簡單,尤其是在您可能不希望對應用程式域模型施加此類限制,或者您無法控制要序列化的物件時,這種情況在使用第三方庫時尤其常見(例如,考慮使用具有 Coordinate
型別的地理空間 API)。
要啟用 PDX,請使用 @EnablePdx
註解您的應用程式類,如下所示
ClientCache
應用程式@SpringBootApplication
@ClientCacheApplication
@EnablePdx
public class ClientApplication { .. }
通常,應用程式的域物件型別要麼實現 org.apache.geode.pdx.PdxSerializable
介面,要麼您可以實現並註冊 org.apache.geode.pdx.PdxSerializer
介面的非侵入式實現,以處理所有需要序列化的應用程式域物件型別。
不幸的是,Apache Geode 僅允許註冊一個 PdxSerializer
,這意味著所有應用程式域物件型別都需要由單個 PdxSerializer
例項處理。但是,這是一種嚴重的反模式,也是一種不可維護的做法。
即使只能向 Apache Geode 註冊一個 PdxSerializer
例項,但為每個應用程式域物件型別建立一個 PdxSerializer
實現也是有意義的。
透過使用 組合軟體設計模式,您可以提供 PdxSerializer
介面的實現,該實現聚合所有特定於應用程式域物件型別的 PdxSerializer
例項,但充當單個 PdxSerializer
例項並進行註冊。
您可以在 Spring 容器中將此組合 PdxSerializer
宣告為託管 Bean,並使用 serializerBeanName
屬性在 @EnablePdx
註解中透過其 Bean 名稱引用此組合 PdxSerializer
。Spring Data for Apache Geode 會代表您負責將其註冊到 Apache Geode。
以下示例展示瞭如何建立自定義組合 PdxSerializer
ClientCache
應用程式,使用自定義的複合 PdxSerializer
@SpringBootApplication
@ClientCacheApplication
@EnablePdx(serializerBeanName = "compositePdxSerializer")
public class ClientApplication {
@Bean
PdxSerializer compositePdxSerializer() {
return new CompositePdxSerializerBuilder()...
}
}
也可以在 Spring 上下文中將 Apache Geode 的 org.apache.geode.pdx.ReflectionBasedAutoSerializer
宣告為 Bean 定義。
或者,您應該使用 Spring Data for Apache Geode 的更強大的 org.springframework.data.gemfire.mapping.MappingPdxSerializer
,它使用 Spring Data 對映元資料和基礎設施應用於序列化過程,以實現比單純反射更有效的處理。
可以使用 @EnablePdx
註解屬性或關聯的配置屬性調整 PDX 的許多其他方面和功能。
有關更多詳細資訊,請參閱 @EnablePdx
註解 Javadoc。
6.11. 配置 Apache Geode 屬性
雖然許多 gemfire.properties 在 SDG 基於註解的配置模型中透過註解方便地封裝和抽象,但不太常用的 Apache Geode 屬性仍然可以透過 @EnableGemFireProperties
註解訪問。
使用 @EnableGemFireProperties
註解您的應用程式類很方便,並且是建立 gemfire.properties
檔案或在啟動應用程式時將 Apache Geode 屬性設定為 Java 系統屬性的不錯替代方案。
我們建議在將應用程式部署到生產環境時,在 gemfire.properties 檔案中設定這些 Apache Geode 屬性。但是,在開發階段,可以根據需要單獨設定這些屬性,以便進行原型設計、除錯和測試。
|
一些不太常用的 Apache Geode 屬性的示例,您通常不必擔心,包括但不限於:ack-wait-threshold
、disable-tcp
、socket-buffer-size
等。
要單獨設定任何 Apache Geode 屬性,請使用 @EnableGemFireProperties
註解您的應用程式類,並使用相應的屬性設定要更改的 Apache Geode 屬性,使其與 Apache Geode 設定的預設值不同,如下所示
ClientCache
應用程式@SpringBootApplication
@ClientCacheApplication
@EnableGemFireProperties(conflateEvents = true, socketBufferSize = 16384)
public class ClientApplication { .. }
請記住,一些 Apache Geode 屬性是特定於客戶端的(例如,conflateEvents
),而另一些是特定於伺服器的(例如,distributedSystemId
、enableNetworkPartitionDetection
、enforceUniqueHost
、memberTimeout
、redundancyZone
等)。
有關 Apache Geode 屬性的更多詳細資訊,請參閱 此處。
6.12. 配置區域
到目前為止,除了 PDX 之外,我們的討論都集中在配置 Apache Geode 的更多管理功能:建立快取例項、啟動嵌入式服務、啟用日誌記錄和統計資訊、配置 PDX 以及使用 gemfire.properties
來影響低階配置和行為。雖然所有這些配置選項都很重要,但它們都沒有直接與您的應用程式相關。換句話說,我們仍然需要一些地方來儲存我們的應用程式資料,並使其普遍可用和可訪問。
以前,Spring Data for Apache Geode 使用者需要透過編寫非常詳細的 Spring 配置元資料來顯式定義和宣告應用程式用來儲存資料的區域,無論是使用 SDG 的 API 中的 FactoryBeans
與 Spring 的 基於 Java 的容器配置,還是使用 XML。
以下示例演示瞭如何在 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。
<gfe:partitioned-region id="exampleRegion" name="Example" persistent="true">
...
</gfe:partitioned-region>
雖然 Java 和 XML 配置都不難指定,但它們都可能很繁瑣,尤其是在應用程式需要大量區域的情況下。許多基於關係資料庫的應用程式可能擁有數百甚至數千個表。
手動定義和宣告所有這些區域將很繁瑣且容易出錯。現在,有了一種更好的方法。
現在,您可以根據其應用程式域物件(實體)本身來定義和配置區域。您不再需要在 Spring 配置元資料中顯式定義 Region
Bean 定義,除非您需要更細粒度的控制。
為了簡化區域建立,Spring Data for Apache Geode 將 Spring Data Repositories 的使用與使用新的 @EnableEntityDefinedRegions
註解的基於註解的配置的表達能力相結合。
大多數 Spring Data 應用程式開發人員應該已經熟悉 Spring Data 儲存庫抽象 和 Spring Data for Apache Geode 的 實現/擴充套件,它經過專門定製以最佳化 Apache Geode 的資料訪問操作。 |
首先,應用程式開發人員從定義應用程式的域物件(實體)開始,如下所示
@Region("Books")
class Book {
@Id
private ISBN isbn;
private Author author;
private Category category;
private LocalDate releaseDate;
private Publisher publisher;
private String title;
}
接下來,透過擴充套件 Spring Data Commons 的 org.springframework.data.repository.CrudRepository
介面,定義一個基本的 Books
儲存庫,如下所示
interface BookRepository extends CrudRepository<Book, ISBN> { .. }
org.springframe.data.repository.CrudRepository
是一個數據訪問物件 (DAO),它提供基本的資料訪問操作 (CRUD) 以及對簡單查詢的支援(例如 findById(..)
)。您可以透過在儲存庫介面上宣告查詢方法來定義額外的、更復雜的查詢(例如,List<BooK> findByAuthor(Author author);
)。
在幕後,Spring Data for Apache Geode 在 Spring 容器啟動時提供應用程式儲存庫介面的實現。只要您遵循 約定,SDG 甚至會實現您定義的查詢方法。
現在,當您定義 Book
類時,您還透過在實體型別上宣告 Spring Data for Apache Geode 對映註釋 @Region
,指定了 Book
例項對映(儲存)到的區域。當然,如果儲存庫介面(在本例中為 BookRepository
)的型別引數中引用的實體型別(在本例中為 Book
)沒有使用 @Region
進行註釋,則該名稱將從實體型別的簡單類名(在本例中也為 Book
)派生。
Spring Data for Apache Geode 使用對映上下文來確定執行時所需的所有區域,該上下文包含應用程式中定義的所有實體的對映元資料。
要啟用和使用此功能,請使用 @EnableEntityDefinedRegions
註釋應用程式類,如下所示
@SpringBootApplication
@ClientCacheApplication
@EnableEntityDefinedRegions(basePackages = "example.app.domain")
@EnableGemfireRepositories(basePackages = "example.app.repo")
class ClientApplication { .. }
在應用程式中使用 Spring Data 儲存庫時,從實體類建立區域最有用。Spring Data for Apache Geode 的儲存庫支援透過 @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
註解)之外,您還可以使用 include
和 exclude
過濾器,它們具有與 org.springframework.context.annotation.ComponentScan.Filter
註解相同的語義。
有關更多詳細資訊,請參閱 @EnableEntityDefinedRegions
註解 Javadoc。
6.12.1. 配置型別特定的區域
Apache Geode 支援許多不同的 區域型別。每種型別對應於區域的 DataPolicy
,它決定了區域中的資料將如何管理(例如,分散式、複製等)。
其他配置設定(例如區域的 scope )也會影響資料的管理方式。有關更多詳細資訊,請參閱 Apache Geode 使用者指南中的 “儲存和分佈選項”。
|
當您使用泛型 @Region
對映註解對應用程式域物件型別進行註解時,Spring Data for Apache Geode 會決定建立哪種型別的區域。SDG 的預設策略在確定要建立的區域型別時會考慮快取型別。
例如,如果您使用 @ClientCacheApplication
註解將應用程式宣告為 ClientCache
,SDG 預設情況下會建立一個客戶端 PROXY
Region
。或者,如果您使用 @PeerCacheApplication
或 @CacheServerApplication
註解將應用程式宣告為對等 Cache
,SDG 預設情況下會建立一個伺服器 PARTITION
Region
。
當然,您始終可以在需要時覆蓋預設值。要覆蓋 Spring Data for Apache Geode 應用的預設值,引入了四個新的區域對映註解
-
@ClientRegion
-
@LocalRegion
-
@PartitionRegion
-
@ReplicateRegion
@ClientRegion
對映註解是特定於客戶端應用程式的。上面列出的所有其他 Region 對映註解只能在具有嵌入式對等 Cache
的伺服器應用程式中使用。
客戶端應用程式有時需要建立和使用僅限本地的 Region,也許是為了聚合來自其他 Region 的資料,以便在本地分析資料並執行應用程式代表使用者執行的某些功能。在這種情況下,資料不需要分發回伺服器,除非其他應用程式需要訪問結果。此 Region 甚至可能是臨時的,並在使用後被丟棄,這可以透過 Region 本身的空閒超時 (TTI) 和生存時間 (TTL) 過期策略來實現。(有關過期策略的更多資訊,請參見“配置過期”。)
Region 級別的空閒超時 (TTI) 和生存時間 (TTL) 過期策略獨立於條目級 TTI 和 TTL 過期策略,並且與之不同。 |
無論如何,如果您想建立一個僅限本地的客戶端 Region,其中資料不會分發回伺服器上具有相同名稱的對應 Region,您可以宣告 @ClientRegion
對映註解並將 shortcut
屬性設定為 ClientRegionShortcut.LOCAL
,如下所示
ClientCache
應用程式@ClientRegion(shortcut = ClientRegionShortcut.LOCAL)
class ClientLocalEntityType { .. }
所有 Region 型別特定的註解都提供額外的屬性,這些屬性既是跨 Region 型別通用的,也是特定於該型別 Region 的。例如,PartitionRegion
註解中的 collocatedWith
和 redundantCopies
屬性僅適用於伺服器端 PARTITION
Region。
有關 Apache Geode Region 型別的更多詳細資訊,請參見 此處。
6.12.2. 配置的叢集定義的 Region
除了 @EnableEntityDefinedRegions
註解之外,Spring Data for Apache Geode 還提供了反向註解 @EnableClusterDefinedRegions
。與其將您的 Region 基於從您的應用程式用例 (UC) 和需求中定義和驅動的實體類(最常見和合乎邏輯的方法),您還可以從連線 ClientCache
應用程式的叢集中已定義的 Region 中宣告您的 Region。
這使您可以使用伺服器叢集作為資料定義的主要來源來集中您的配置,並確保叢集的所有客戶端應用程式都具有一致的配置。這在快速擴充套件大量相同客戶端應用程式例項以處理雲管理環境中增加的負載時特別有用。
想法是,與其讓客戶端應用程式驅動資料字典,不如讓使用者使用 Apache Geode 的 *Gfsh* CLI shell 工具定義區域。這樣做的好處是,當向叢集新增更多節點時,這些節點也會擁有並共享相同的配置,因為 Apache Geode 的 *叢集配置服務* 會記住它。
例如,使用者可以在 *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
使用 Apache Geode 的 *叢集配置服務*,向伺服器叢集新增任何額外的節點以處理增加的負載(在後端)時,這些節點也會擁有相同的配置,例如
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” 區域,如下所示
@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 儲存庫定義,將其對映到“Books” 區域,如下所示
interface BookRepository extends CrudRepository<Book, ISBN> {
...
}
然後,您可以將自定義的 BooksDataAccessObject
或 BookRepository
注入到您的應用程式服務元件中,以執行所需的任何業務功能。
6.12.3. 配置驅逐
使用 Apache Geode 管理資料是一項活躍的任務。通常需要進行調整,並且您必須使用多種功能(例如,驅逐和 過期)來有效地管理 Apache Geode 中的記憶體資料。
鑑於 Apache Geode 是一個記憶體資料網格 (IMDG),資料在記憶體中進行管理,並分發到參與叢集的其他節點,以最大程度地減少延遲,最大限度地提高吞吐量,並確保資料高度可用。由於並非所有應用程式的資料通常都適合記憶體(即使在整個節點叢集中,更不用說單個節點了),您可以透過向叢集新增新節點來增加容量。這通常被稱為線性擴充套件(而不是擴充套件,這意味著新增更多記憶體、更多 CPU、更多磁碟或更多網路頻寬——基本上是更多系統資源來處理負載)。
儘管如此,即使使用節點叢集,通常也必須將最重要的資料保留在記憶體中。記憶體不足,甚至接近滿負荷,很少,如果有的話,是一件好事。停止世界的 GC 甚至更糟,OutOfMemoryErrors
會使您的應用程式徹底停止。
因此,為了幫助管理記憶體並保留最重要的資料,Apache Geode 支援最近最少使用 (LRU) 驅逐。也就是說,Apache Geode 使用最近最少使用演算法根據區域條目上次訪問的時間驅逐區域條目。
要啟用驅逐,請使用 @EnableEviction
註釋應用程式類,如下所示
@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
註釋,每個註釋都針對一個或多個需要應用驅逐策略的區域。
此外,您可以參考 Apache Geode 的自定義實現 org.apache.geode.cache.util.ObjectSizer
介面,該介面可以定義為 Spring 容器中的 Bean,並使用 objectSizerName
屬性按名稱引用。
ObjectSizer
允許您定義用於評估和確定儲存在 Region 中的物件大小的標準。
有關驅逐配置選項的完整列表,請參閱 @EnableEviction
註釋 Javadoc。
有關 Apache Geode 驅逐的更多詳細資訊,請參閱 此處。
6.12.4. 配置過期
除了 驅逐 之外,過期也可以用於透過允許儲存在 Region 中的條目過期來管理記憶體。Apache Geode 支援生存時間 (TTL) 和空閒超時 (TTI) 條目過期策略。
Spring Data for Apache Geode 的基於註釋的過期配置基於 Spring Data for Apache Geode 版本 1.5 中新增的早期和現有的條目過期註釋支援。
本質上,Spring Data for Apache Geode 的過期註釋支援基於 Apache Geode 的自定義實現 org.apache.geode.cache.CustomExpiry
介面。此 o.a.g.cache.CustomExpiry
實現檢查儲存在 Region 中的使用者應用程式域物件,以檢視是否存在型別級過期註釋。
Spring Data for Apache Geode 提供以下過期註釋
-
過期
-
IdleTimeoutExpiration
-
TimeToLiveExpiration
應用程式域物件型別可以使用一個或多個過期註釋進行註釋,如下所示
@Region("Books")
@TimeToLiveExpiration(timeout = 30000, action = "INVALIDATE")
class Book { .. }
要啟用過期,請使用 @EnableExpiration
註釋應用程式類,如下所示
@SpringBootApplication
@PeerCacheApplication
@EnableExpiration
class ServerApplication { .. }
除了應用程式域物件型別級過期策略之外,您還可以使用 @EnableExpiration
註釋直接在 Region 基礎上逐個 Region 地配置過期策略,如下所示
@SpringBootApplication
@PeerCacheApplication
@EnableExpiration(policies = {
@ExpirationPolicy(regionNames = "Books", types = ExpirationType.TIME_TO_LIVE),
@ExpirationPolicy(regionNames = { "Customers", "Orders" }, timeout = 30000,
action = ExpirationActionType.LOCAL_DESTROY)
})
class ServerApplication { .. }
前面的示例為 Books
、Customers
和 Orders
Region 設定了過期策略。
過期策略通常在伺服器中的 Region 上設定。
有關過期配置選項的完整列表,請參閱 @EnableExpiration
註解 Javadoc。
有關 Apache Geode 過期的更多詳細資訊,請參閱 此處。
6.12.5. 配置壓縮
Apache Geode 允許您透過使用可插拔的 Compressors
(或不同的壓縮編解碼器)來壓縮記憶體中的區域值。預設情況下,Apache Geode 使用 Google 的 Snappy 壓縮庫。
要啟用壓縮,請使用 @EnableCompression
註解應用程式類,如下所示
@SpringBootApplication
@ClientCacheApplication
@EnableCompression(compressorBeanName = "MyCompressor", regionNames = { "Customers", "Orders" })
class ClientApplication { .. }
compressorBeanName 和 regionNames 屬性都不是必需的。
|
compressorBeanName
預設值為 SnappyCompressor
,啟用 Apache Geode 的 SnappyCompressor
。
regionNames
屬性是一個區域名稱陣列,指定啟用了壓縮的區域。預設情況下,如果未顯式設定 regionNames
屬性,則所有區域都會壓縮值。
或者,您可以在 application.properties 檔案中使用 spring.data.gemfire.cache.compression.compressor-bean-name 和 spring.data.gemfire.cache.compression.region-names 屬性來設定和配置這些 @EnableCompression 註解屬性的值。
|
要使用 Apache Geode 的區域壓縮功能,您必須在應用程式的 pom.xml 檔案(對於 Maven)或 build.gradle 檔案(對於 Gradle)中包含 org.iq80.snappy:snappy 依賴項。這僅在您使用 Apache Geode 對區域壓縮的預設支援時才需要,預設情況下該支援使用 SnappyCompressor 。當然,如果您使用其他壓縮庫,則需要在應用程式的類路徑上包含該壓縮庫的依賴項。此外,您需要實現 Apache Geode 的 Compressor 介面以適應您選擇的壓縮庫,將其定義為 Spring 壓縮器中的 bean,並將 compressorBeanName 設定為此自定義 bean 定義。
|
有關更多詳細資訊,請參閱 @EnableCompression
註解 Javadoc。
有關 Apache Geode 壓縮的更多詳細資訊,請參見 此處。
6.12.6. 配置堆外記憶體
使用 Apache Geode 的堆外記憶體支援是減少 JVM 堆記憶體壓力和最大程度減少 GC 活動的另一種有效方法。
與將區域條目儲存在 JVM 堆上不同,條目儲存在系統的主記憶體中。如 Apache Geode 使用者指南 中所述,堆外記憶體通常在儲存的物件大小一致、大部分小於 128K 且不需要頻繁反序列化時效果最佳。
要啟用堆外記憶體,請使用 @EnableOffHeap
註釋應用程式類,如下所示
@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-size 和 spring.data.gemfire.cache.off-heap.region-names 屬性來設定和配置這些 @EnableOffHeap 註釋屬性的值。
|
有關更多詳細資訊,請參見 @EnableOffHeap
註釋 Javadoc。
6.12.7. 配置磁碟儲存
或者,您可以配置區域將資料持久化到磁碟。您還可以配置區域在區域條目被逐出時將資料溢位到磁碟。在這兩種情況下,都需要一個 DiskStore
來持久化和/或溢位資料。當未為具有永續性或溢位的區域顯式配置 DiskStore
時,Apache Geode 使用 DEFAULT
DiskStore
。
我們建議在將資料持久化和/或溢位到磁碟時定義特定於區域的 DiskStores
。
Spring Data for Apache Geode 透過使用 @EnableDiskStore
和 @EnableDiskStores
註釋註釋應用程式類,為定義和建立應用程式區域 DiskStores
提供註釋支援。
@EnableDiskStores 是一個複合註釋,用於聚合一個或多個 @EnableDiskStore 註釋。
|
例如,雖然 Book
資訊可能主要來自某些外部資料來源(例如亞馬遜)的參考資料,但 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 Apache Geode中基於註解的配置模型中的其他註解一樣,@EnableDiskStore
和@EnableDiskStores
都有許多屬性以及相關的配置屬性,用於在執行時自定義建立的DiskStores
。
此外,@EnableDiskStores
註解定義了某些適用於所有DiskStore
的通用DiskStore
屬性,這些DiskStore
是由@EnableDiskStore
註解與@EnableDiskStores
註解本身組合建立的。單個DiskStore
配置會覆蓋特定的全域性設定,但@EnableDiskStores
註解方便地定義了適用於註解聚合的所有DiskStores
的通用配置屬性。
Spring Data for Apache Geode還提供了DiskStoreConfigurer
回撥介面,可以在Java配置中宣告該介面,並用它來代替配置屬性在執行時自定義DiskStore
,如下例所示
@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。
有關Apache Geode區域永續性和溢位(使用DiskStores)的更多詳細資訊,請參見此處。
6.12.8. 配置索引
除非可以訪問資料,否則在區域中儲存資料沒有多大用處。
除了Region.get(key)
操作(尤其是在預先知道鍵的情況下),通常透過對包含資料的區域執行查詢來檢索資料。使用Apache Geode,查詢是使用物件查詢語言(OQL)編寫的,客戶端希望訪問的特定資料集在查詢的謂詞中表達(例如,SELECT * FROM /Books b WHERE b.author.name = 'Jon Doe'
)。
通常,沒有索引的查詢效率低下。在沒有索引的情況下執行查詢時,Apache Geode執行相當於完整表掃描的操作。
Spring Data for Apache Geode使在儲存和訪問資料的區域上建立索引變得容易。我們不再需要使用Spring配置顯式宣告Index
bean定義,而是可以像下面這樣在Java中建立Index
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 定義,如下所示
<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 Apache Geode 中,@Id
註釋的欄位或屬性用作儲存條目時 Region 中的鍵。
-
@Id
註釋的欄位或屬性會導致建立 Apache GeodeKEY
索引。 -
@Indexed
註釋的欄位或屬性會導致建立 Apache GeodeHASH
索引(預設值)。 -
@LuceneIndexed
註釋的欄位或屬性會導致建立 Apache Geode Lucene 索引,該索引用於 Apache Geode 的 Lucene 整合和支援的基於文字的搜尋。
當使用 @Indexed
註釋而不設定任何屬性時,索引的 name
、expression
和 fromClause
將從添加了 @Indexed
註釋的類的欄位或屬性派生。expression
恰好是欄位或屬性的名稱。fromClause
從域物件的類的 @Region
註釋派生,或者如果未指定 @Region
註釋,則從域物件的類的簡單名稱派生。
當然,您可以顯式設定任何 @Indexed
註釋屬性以覆蓋 Spring Data for Apache Geode 提供的預設值。
@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
註釋應用程式類,如下所示
@SpringBootApplication
@PeerCacheApplication
@EnableEntityDefinedRegions
@EnableIndexing
class ServerApplication { .. }
除非還聲明瞭@EnableEntityDefinedRegions ,否則@EnablingIndexing 註釋無效。本質上,索引是從實體類型別上的欄位或屬性定義的,並且必須掃描實體類以檢查實體的欄位和屬性中是否存在索引註釋。如果沒有此掃描,則無法找到索引註釋。我們還強烈建議您限制掃描範圍。
|
雖然 Spring Data for Apache Geode 儲存庫目前不支援 Lucene 查詢,但 SDG 透過使用熟悉的 Spring 模板設計模式為 Apache Geode Lucene 查詢提供了全面的支援。
最後,我們以一些使用索引時需要牢記的額外提示來結束本節
-
雖然執行 OQL 查詢不需要 OQL 索引,但執行 Lucene 基於文字的搜尋需要 Lucene 索引。
-
OQL 索引不會持久儲存到磁碟。它們只在記憶體中維護。因此,當 Apache Geode 節點重新啟動時,必須重建索引。
-
您還需要注意維護索引相關的開銷,特別是由於索引專門儲存在記憶體中,尤其是在更新 Region 條目時。索引“維護”可以配置為非同步任務。
當您重新啟動需要重建索引的 Spring 應用程式時,您可以使用的另一種最佳化方法是首先預先定義所有索引,然後一次性建立它們,這在 Spring Data for Apache Geode 中是在 Spring 容器重新整理時發生的。
您可以透過將@EnableIndexing
註釋上的define
屬性設定為true
來預先定義索引,然後一次性建立它們。
有關更多詳細資訊,請參閱 Apache Geode 使用者指南中的“一次建立多個索引”。
建立合理的索引是一項重要的任務,因為設計不當的索引可能會弊大於利。
有關配置選項的完整列表,請參閱 @Indexed
註解和 @LuceneIndexed
註解的 Javadoc 文件。
有關 Apache Geode OQL 查詢的更多詳細資訊,請 點選此處。
有關 Apache Geode 索引的更多詳細資訊,請 點選此處。
有關 Apache Geode Lucene 查詢的更多詳細資訊,請 點選此處。
6.13. 配置持續查詢
Apache Geode 的另一個非常重要且有用的功能是 持續查詢。
在網際網路時代,事件和資料流來自各個地方。能夠處理和處理大量資料流並即時響應事件對於許多應用程式來說越來越重要。自動駕駛汽車就是一個例子。能夠即時接收、過濾、轉換、分析和處理資料是即時應用程式的關鍵差異和特徵。
幸運的是,Apache Geode 在這方面領先於時代。透過使用持續查詢 (CQ),客戶端應用程式可以表達其感興趣的資料或事件,並註冊監聽器來處理和處理發生的事件。客戶端應用程式可能感興趣的資料以 OQL 查詢的形式表達,其中查詢謂詞用於過濾或識別感興趣的資料。當資料發生更改或新增並且它與註冊的 CQ 的查詢謂詞中定義的條件匹配時,將通知客戶端應用程式。
Spring Data for Apache Geode 使得定義和註冊 CQ 變得容易,以及一個關聯的監聽器來處理和處理 CQ 事件,而無需 Apache Geode 的所有管道。SDG 的基於註解的 CQ 配置建立在 持續查詢監聽器容器 中現有的持續查詢支援之上。
例如,假設一個銀行應用程式註冊了對每個客戶的支票賬戶的興趣,以檢測透支取款並透過應用透支保護或通知客戶來處理此事件。然後,應用程式可能會註冊以下 CQ
ClientCache
應用程式。@SpringBootApplication
@ClientCacheApplication(subcriptionEnabled = true)
@EnableContinuousQueries
class PublisherPrintApplication {
@ContinuousQuery(name = "OverdraftProtection", query = "SELECT * FROM /CheckingAccount ca WHERE ca.balance < 0.0")
void handleOverdraft(CqEvent event) {
// Quick!!! Put more money into the checking account or notify the customer of the checking account!
}
}
要啟用持續查詢,請使用 @EnableContinuousQueries
註解您的應用程式類。
定義連續查詢包括使用 @ContinuousQuery
註解(類似於 SDG 的 Function 註解的 POJO 方法)來註釋任何 Spring @Component
註解的 POJO 類方法。使用 @ContinuousQuery
註解定義的 POJO 方法會在每次新增或更改與查詢謂詞匹配的資料時被呼叫。
此外,POJO 方法簽名應符合 ContinuousQueryListener
和 ContinuousQueryListenerAdapter
部分中概述的要求。
有關可用屬性和配置設定的更多詳細資訊,請參閱 @EnableContinuousQueries
和 @ContinuousQuery
註解 Javadoc。
有關 Spring Data for Apache Geode 的連續查詢支援的更多詳細資訊,請參閱 此處。
有關 Apache Geode 的連續查詢的更多詳細資訊,請參閱 此處。
6.14. 配置 Spring 的快取抽象
使用 Spring Data for Apache Geode,Apache Geode 可用作 Spring 的 快取抽象 中的快取提供者。
在 Spring 的快取抽象中,快取註解(例如 @Cacheable
)標識在呼叫可能很昂貴的操作之前執行快取查詢的快取。應用程式服務方法的結果在呼叫操作後被快取。
在 Spring Data for Apache Geode 中,Spring Cache
直接對應於 Apache Geode Region。在呼叫任何快取註釋的應用程式服務方法之前,Region 必須存在。這適用於任何 Spring 的快取註解(即 @Cacheable
、@CachePut
和 @CacheEvict
),這些註解標識在服務操作中使用的快取。
例如,我們的釋出商的銷售點 (PoS) 應用程式可能具有在銷售交易期間確定或查詢 Book
的 Price
的功能,如下例所示
@Service
class PointOfSaleService
@Cacheable("BookPrices")
Price runPriceCheckFor(Book book) {
...
}
@Transactional
Receipt checkout(Order order) {
...
}
...
}
為了簡化您在將 Spring Data for Apache Geode 與 Spring 的快取抽象一起使用時的工作,我們在基於註解的配置模型中添加了兩個新功能。
請考慮以下 Spring 快取配置
@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 Apache Geode 的新功能,您可以將相同的快取配置簡化為以下內容
@EnableGemfireCaching
@EnableCachingDefinedRegions
class CachingConfiguration {
@Bean("PointOfSaleService")
PointOfSaleService pointOfSaleService(..) {
return new PointOfSaleService(..);
}
}
首先,@EnableGemfireCaching
註解替換了 Spring 的 @EnableCaching
註解,以及在 Spring 配置中宣告顯式 CacheManager
bean 定義(名為“cacheManager”)的需要。
其次,@EnableCachingDefinedRegions
註解,類似於“配置區域”中描述的 @EnableEntityDefinedRegions
註解,會檢查整個 Spring 應用程式,快取帶註解的服務元件以識別應用程式執行時所需的所有快取,並在應用程式啟動時為這些快取建立 Apache Geode 中的區域。
建立的區域對於建立區域的應用程式程序是本地的。如果應用程式是 peer Cache
,則區域僅存在於應用程式節點上。如果應用程式是 ClientCache
,則 SDG 會建立客戶端 PROXY
區域,並期望這些區域在叢集中的伺服器上已經存在,並且具有相同的名稱。
SDG 無法使用 Spring CacheResolver 在執行時確定服務方法所需的快取,以解析操作中使用的快取。
|
SDG 還支援應用程式服務元件上的 JCache(JSR-107)快取註解。有關在 JCache 快取註解代替的地方使用的等效 Spring 快取註解,請參閱核心 Spring 框架參考指南。 |
有關在 Spring 的快取抽象中使用 Apache Geode 作為快取提供程式的更多詳細資訊,請參閱 “支援 Spring 快取抽象” 部分。
有關 Spring 快取抽象的更多詳細資訊,請參閱 此處。
6.15. 配置叢集配置推送
這可能是 Spring Data for Apache Geode 中最令人興奮的新功能。
當客戶端應用程式類使用 @EnableClusterConfiguration
註解時,任何在 Spring 容器中定義和宣告為 bean 的區域或索引(由客戶端應用程式定義)都會“推送”到客戶端連線到的伺服器叢集。不僅如此,這種“推送”是以 Apache Geode 在使用 HTTP 時記住客戶端推送的配置的方式執行的。如果叢集中的所有節點都宕機,它們會以與之前相同的配置恢復。如果向叢集新增新的伺服器,它將獲取相同的配置。
從某種意義上說,此功能與使用 Gfsh 手動在叢集中的所有伺服器上建立區域和索引並沒有太大區別。不同的是,現在使用 Spring Data for Apache Geode,您不再需要使用 Gfsh 來建立區域和索引。您的 Spring Boot 應用程式,在 Spring Data for Apache Geode 的強大功能的支援下,已經包含了建立區域和索引所需的所有配置元資料。
當您使用 Spring Data Repository 抽象時,我們知道您的應用程式需要的所有區域(例如由 @Region
註釋的實體類定義的區域)和索引(例如由 @Indexed
註釋的實體欄位和屬性定義的索引)。
當您使用 Spring 的快取抽象時,我們還知道應用程式服務元件所需的快取註釋中標識的所有快取的區域。
從本質上講,您已經告訴我們所有需要知道的資訊,只需使用 Spring 框架開發您的應用程式,只需使用其所有 API 和功能,無論是在註釋元資料、Java、XML 中表達,還是其他方式,無論是用於配置、對映還是任何目的。
關鍵是,您可以專注於應用程式的業務邏輯,同時使用框架的功能和支援基礎設施(例如 Spring 的快取抽象、Spring Data Repositories、Spring 的事務管理等等),Spring Data for Apache Geode 會代表您處理所有這些框架功能所需的 Apache Geode 管道。
將配置從客戶端推送到叢集中的伺服器並讓叢集記住它,這部分得益於 Apache Geode 的 叢集配置 服務。Apache Geode 的叢集配置服務也是 Gfsh 用於記錄使用者從 shell 向叢集發出的與模式相關的更改(例如,gfsh> create region --name=Example --type=PARTITION
)的相同服務。
當然,由於叢集可能會“記住”先前執行中客戶端推送的先前配置,因此 Spring Data for Apache Geode 會謹慎地避免覆蓋伺服器中已定義的任何現有區域和索引。這在區域已經包含資料時尤其重要!
目前,沒有選項可以覆蓋任何現有的區域或索引定義。要重新建立區域或索引,您必須使用 Gfsh 先銷燬區域或索引,然後重新啟動客戶端應用程式,以便將配置再次推送到伺服器。或者,您可以使用 Gfsh 手動(重新)定義區域和索引。 |
與 Gfsh 不同,Spring Data for Apache Geode 僅支援從客戶端在伺服器上建立區域和索引。對於高階配置和用例,您應該使用 Gfsh 管理(伺服器端)叢集。 |
要使用此功能,您必須在 Spring、Apache Geode ClientCache 應用程式的類路徑中顯式宣告 org.springframework:spring-web 依賴項。
|
考慮以下配置中表達的力量
ClientCache
應用程式@SpringBootApplication
@ClientCacheApplication
@EnableCachingDefinedRegions
@EnableEntityDefinedRegions
@EnableIndexing
@EnableGemfireCaching
@EnableGemfireRepositories
@EnableClusterConfiguration
class ClientApplication { .. }
您將立即獲得一個具有 Apache Geode ClientCache
例項、Spring Data Repositories、Spring 的快取抽象(以 Apache Geode 作為快取提供者)的 Spring Boot 應用程式(其中區域和索引不僅在客戶端建立,而且被推送到叢集中的伺服器)。
從那裡開始,您只需要執行以下操作
-
定義應用程式的域模型物件,並使用對映和索引註釋進行註釋。
-
定義儲存庫介面以支援每個實體型別的基本資料訪問操作和簡單查詢。
-
定義包含處理實體的業務邏輯的服務元件。
-
在需要快取、事務行為等的 service 方法上宣告相應的註釋。
在本例中,與應用程式後端服務(如 Apache Geode)所需的架構和管道無關。資料庫使用者具有類似的功能。現在 Spring 和 Apache Geode 開發人員也擁有了。
當與以下 Spring Data for Apache Geode 註釋結合使用時,此應用程式幾乎無需任何努力即可開始執行
-
@EnableContinuousQueries
-
@EnableGemfireFunctionExecutions
-
@EnableGemfireCacheTransactions
有關更多詳細資訊,請參閱 @EnableClusterConfiguration
註釋 Javadoc。
6.16. 配置 SSL
將資料序列化以透過網路傳輸與在傳輸過程中保護資料一樣重要。當然,在 Java 中實現此目的的常用方法是使用安全套接字擴充套件 (SSE) 和傳輸層安全 (TLS)。
要啟用 SSL,請使用 @EnableSsl
註釋您的應用程式類,如下所示
ClientCache
應用程式@SpringBootApplication
@ClientCacheApplication
@EnableSsl
public class ClientApplication { .. }
然後,您需要設定必要的 SSL 配置屬性或屬性:金鑰庫、使用者名稱/密碼等。
您可以分別使用 SSL 配置不同的 Apache Geode 元件(GATEWAY
、HTTP
、JMX
、LOCATOR
和 SERVER
),也可以使用 CLUSTER
列舉值將它們集體配置為使用 SSL。
您可以使用巢狀的 @EnableSsl
註釋、components
屬性以及來自 Component
列舉的列舉值來指定應應用 SSL 配置設定的 Apache Geode 元件,如下所示
ClientCache
應用程式@SpringBootApplication
@ClientCacheApplication
@EnableSsl(components = { GATEWAY, LOCATOR, SERVER })
public class ClientApplication { .. }
此外,您還可以使用相應的註釋屬性或關聯的配置屬性來指定元件級 SSL 配置(ciphers
、protocols
和 keystore
/truststore
資訊)。
有關更多詳細資訊,請參閱 @EnableSsl
註釋 Javadoc。
有關 Apache Geode SSL 支援的更多詳細資訊,請參閱 此處。
6.17. 配置安全性
毫無疑問,應用程式安全性極其重要,Spring Data for Apache Geode 為保護 Apache Geode 客戶端和伺服器提供了全面的支援。
最近,Apache Geode 引入了一個新的 整合安全 框架(取代了舊的身份驗證和授權安全模型)來處理身份驗證和授權。這個新安全框架的主要功能和優勢之一是它與 Apache Shiro 整合,因此可以將身份驗證和授權請求委託給 Apache Shiro 來執行安全策略。
本節的其餘部分將演示 Spring Data for Apache Geode 如何進一步簡化 Apache Geode 的安全故事。
6.17.1. 配置伺服器安全
您可以透過多種不同的方式為 Apache Geode 叢集中的伺服器配置安全。
-
實現 Apache Geode 的
org.apache.geode.security.SecurityManager
介面,並將 Apache Geode 的security-manager
屬性設定為使用完全限定的類名引用您的應用程式SecurityManager
實現。或者,使用者可以構造並初始化其SecurityManager
實現的例項,並在建立 Apache Geode 對等Cache
時使用 CacheFactory.setSecurityManager(:SecurityManager) 方法設定它。 -
建立一個 Apache Shiro
shiro.ini
檔案,其中包含為您的應用程式定義的使用者、角色和許可權,然後將 Apache Geode 的security-shiro-init
屬性設定為引用此shiro.ini
檔案,該檔案必須在CLASSPATH
中可用。 -
僅使用 Apache Shiro,使用 Spring Data for Apache Geode 的新
@EnableSecurity
註解註釋您的 Spring Boot 應用程式類,並在 Spring 容器中定義一個或多個 Apache ShiroRealms
作為 bean,以訪問您的應用程式的安全元資料(即授權使用者、角色和許可權)。
第一種方法的問題在於您必須實現自己的 SecurityManager
,這可能非常繁瑣且容易出錯。實現自定義 SecurityManager
在從儲存元資料的任何資料來源(例如 LDAP 或甚至專有內部資料來源)訪問安全元資料方面提供了一些靈活性。但是,這個問題已經透過配置和使用 Apache Shiro Realms
解決,後者更廣為人知且不特定於 Apache Geode。
第二種方法是使用 Apache Shiro INI 檔案,雖然略好一些,但首先您仍然需要熟悉 INI 檔案格式。此外,INI 檔案是靜態的,在執行時不容易更新。
第三種方法是最理想的,因為它遵循廣為人知且業界認可的概念(即 Apache Shiro 的安全框架),並且易於設定,如下例所示
@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 支援的任何 Realm
|
-
支援 INI 格式 的
Realm
。
您甚至可以建立 Apache Shiro Realm
的自定義實現。
有關更多詳細資訊,請參閱 Apache Shiro 的 關於 Realms 的文件。
當 Apache Shiro 位於叢集中伺服器的 CLASSPATH
上,並且一個或多個 Apache Shiro Realm
已在 Spring 容器中定義為 bean 時,Spring Data for Apache Geode 會檢測到此配置,並使用 Apache Shiro 作為安全提供程式來保護您的 Apache Geode 伺服器,前提是使用了 @EnableSecurity
註解。
您可以在此 spring.io 部落格文章 中找到有關 Spring Data for Apache Geode 支援 Apache Geode 使用 Apache Shiro 的新整合安全框架的更多資訊。 |
有關可用屬性和相關配置屬性的更多詳細資訊,請參閱 @EnableSecurity
註解 Javadoc。
有關 Apache Geode 安全的更多詳細資訊,請參閱 此處。
6.17.2. 配置客戶端安全
如果沒有討論如何保護基於 Spring 的 Apache Geode 快取客戶端應用程式,安全故事將不完整。
Apache Geode 保護客戶端應用程式的過程實際上相當複雜。簡而言之,您需要
-
提供
org.apache.geode.security.AuthInitialize
介面的實現。 -
將 Apache Geode 的
security-client-auth-init
(系統)屬性設定為引用自定義的、應用程式提供的AuthInitialize
介面。 -
在專有的 Apache Geode
gfsecurity.properties
檔案中指定使用者憑據。
Spring Data for Apache Geode 透過使用與伺服器應用程式中使用的相同 @EnableSecurity
註解來簡化所有這些步驟。換句話說,相同的 @EnableSecurity
註解處理客戶端和伺服器應用程式的安全。當用戶決定將應用程式從嵌入式、對等 Cache
應用程式切換到 ClientCache
應用程式時,此功能使操作變得更加容易,例如。只需將 SDG 註解從 @PeerCacheApplication
或 @CacheServerApplication
更改為 @ClientCacheApplication
,就完成了。
實際上,您在客戶端上需要做的只是以下操作
@EnableSecurity
的 Spring 客戶端應用程式@SpringBootApplication
@ClientCacheApplication
@EnableSecurity
class ClientApplication { .. }
然後,您可以定義熟悉的 Spring Boot application.properties
檔案,其中包含所需的使用者名稱和密碼,如下面的示例所示,您就完成了所有設定
application.properties
檔案spring.data.gemfire.security.username=jackBlack
spring.data.gemfire.security.password=b@cK!nB1@cK
預設情況下,Spring Boot 可以在應用程式的 CLASSPATH 根目錄中找到您的 application.properties 檔案。當然,Spring 支援使用其 資源抽象 來定位資源的多種方法。
|
有關可用屬性和相關配置屬性的更多詳細資訊,請參閱 @EnableSecurity
註解 Javadoc。
有關 Apache Geode 安全的更多詳細資訊,請參見 此處。
6.18. 配置提示
以下提示可以幫助您充分利用新的基於註解的配置模型
6.18.1. 配置組織
正如我們在關於 “配置叢集配置推送” 的部分中所看到的,當使用註解啟用許多 Apache Geode 或 Spring Data for Apache Geode 功能時,我們開始在 Spring @Configuration
或 @SpringBootApplication
類上堆疊大量註解。在這種情況下,開始對配置進行一些分隔是有意義的。
例如,請考慮以下宣告
ClientCache
應用程式@SpringBootApplication
@ClientCacheApplication
@EnableContinuousQueries
@EnableCachingDefinedRegions
@EnableEntityDefinedRegions
@EnableIndexing
@EnableGemfireCacheTransactions
@EnableGemfireCaching
@EnableGemfireFunctionExecutions
@EnableGemfireRepositories
@EnableClusterConfiguration
class ClientApplication { .. }
我們可以按以下關注點細分此配置
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 框架來說無關緊要,但我們通常建議以可讀性為目標,為了將來維護程式碼的人(將來可能就是你)。
6.18.2. 其他基於配置的註解
以下 SDG 註解在本參考文件中未討論,原因是該註解支援 Apache Geode 的已棄用功能,或者因為存在更好的替代方法來完成該註解提供的功能
-
@EnableAuth
:啟用 Apache Geode 的舊身份驗證和授權安全模型。(已棄用。Apache Geode 的新整合安全框架可以透過使用 SDG 的@EnableSecurity
註解在客戶端和伺服器上啟用,如“配置安全”中所述。) -
@EnableAutoRegionLookup
:不推薦。本質上,此註解支援查詢在外部配置元資料(如cache.xml
或應用於伺服器的叢集配置)中定義的區域,並自動將這些區域註冊為 Spring 容器中的 bean。此註解對應於 SDG XML 名稱空間中的<gfe:auto-region-lookup>
元素。更多詳細資訊可以在 此處 找到。在使用 Spring 和 Spring Data for Apache Geode 時,使用者通常應該優先使用 Spring 配置。請參閱“配置區域”和“配置叢集配置推送”。 -
@EnableBeanFactoryLocator
:啟用 SDGGemfireBeanFactoryLocator
功能,此功能僅在使用外部配置元資料(例如,cache.xml
)時有用。例如,如果您在cache.xml
中定義的區域上定義了一個CacheLoader
,您仍然可以使用 Spring 配置中定義的,例如,關係型資料庫DataSource
bean 來自動裝配此CacheLoader
。此註解利用了此 SDG 功能,如果您有大量遺留配置元資料(例如,cache.xml
檔案),則可能會有用。 -
@EnableGemFireAsLastResource
:在 全域性 - JTA 事務管理 中與 Apache Geode 進行了討論。 -
@EnableMcast
:啟用 Apache Geode 的舊對等發現機制,該機制使用基於 UDP 的組播網路。(已棄用。請改用 Apache Geode 定位器。請參閱“配置嵌入式定位器”。 -
@EnableRegionDataAccessTracing
:用於除錯目的。此註解透過註冊一個 AOP 方面來啟用對區域執行的所有資料訪問操作的跟蹤,該方面代理在 Spring 容器中宣告為 bean 的所有區域,攔截區域操作並記錄事件。
6.19. 結論
正如我們在前面的部分中瞭解到的,Spring Data for Apache Geode 的新的基於註解的配置模型提供了巨大的力量。希望它能實現其目標,即讓您在使用 Apache Geode 與 Spring 時快速入門和輕鬆使用。
請記住,當您使用新的註解時,您仍然可以使用 Java 配置或 XML 配置。您甚至可以透過在 Spring 的 @Configuration
或 @SpringBootApplication
類上使用 Spring 的 @Import
和 @ImportResource
註解來組合所有三種方法。一旦您明確地提供了一個原本由 Spring Data for Apache Geode 使用其中一個註解提供的 bean 定義,基於註解的配置就會退讓。
在某些情況下,您甚至可能需要回退到 Java 配置,例如在 例如,另一個需要 Java 或 XML 配置的情況是配置 Apache Geode WAN 元件,目前還沒有任何註解配置支援。但是,定義和註冊 WAN 元件只需要在 Spring 的 |
這些註解並非旨在處理所有情況。這些註解旨在幫助您儘可能快速、輕鬆地啟動和執行,尤其是在開發過程中。
我們希望您會喜歡這些新功能!
6.20. 基於註解的配置快速入門
以下部分概述了 SDG 註解,以便您快速入門。
所有註解都提供額外的配置屬性以及相關的 屬性,以便在執行時方便地自定義 Apache Geode 的配置和行為。但是,一般來說,使用特定 Apache Geode 功能不需要任何屬性或相關屬性。只需宣告註解以啟用該功能,您就完成了。有關更多詳細資訊,請參閱每個註解的單獨 Javadoc。 |
6.20.1. 配置 ClientCache
應用程式
要配置和引導 Apache Geode ClientCache
應用程式,請使用以下方法
@SpringBootApplication
@ClientCacheApplication
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
有關更多詳細資訊,請參閱 使用 Spring 配置 Apache Geode 應用程式。
6.20.2. 配置對等 Cache
應用程式
要配置和引導 Apache Geode Peer Cache
應用程式,請使用以下方法
@SpringBootApplication
@PeerCacheApplication
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
如果您想啟用一個允許 ClientCache 應用程式連線到此伺服器的 CacheServer ,只需將 @PeerCacheApplication 註解替換為 @CacheServerApplication 註解。這將啟動一個在“localhost”上執行的 CacheServer ,監聽預設的 CacheServer 埠 40404 。
|
有關更多詳細資訊,請參閱 使用 Spring 配置 Apache Geode 應用程式。
6.20.3. 配置嵌入式 Locator
使用 @EnableLocator
註解您的 Spring @PeerCacheApplication
或 @CacheServerApplication
類,以啟動一個繫結到所有 NIC 並監聽預設 Locator 埠 10334
的嵌入式 Locator,如下所示
@SpringBootApplication
@CacheServerApplication
@EnableLocator
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
@EnableLocator 只能與 Apache Geode 伺服器應用程式一起使用。
|
有關更多詳細資訊,請參閱 配置嵌入式 Locator。
6.20.4. 配置嵌入式 Manager
使用 @EnableManager
註解您的 Spring @PeerCacheApplication
或 @CacheServerApplication
類,以啟動一個繫結到所有 NIC 並監聽預設 Manager 埠 1099
的嵌入式 Manager,如下所示
@SpringBootApplication
@CacheServerApplication
@EnableManager
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
@EnableManager 只能與 Apache Geode 伺服器應用程式一起使用。
|
有關更多詳細資訊,請參閱 配置嵌入式 Manager。
6.20.5. 配置嵌入式 HTTP 伺服器
使用 @EnableHttpService
註解您的 Spring @PeerCacheApplication
或 @CacheServerApplication
類,以啟動一個監聽埠 7070
的嵌入式 HTTP 伺服器(Jetty),如下所示
@SpringBootApplication
@CacheServerApplication
@EnableHttpService
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
@EnableHttpService 只能與 Apache Geode 伺服器應用程式一起使用。
|
有關更多詳細資訊,請參閱 配置嵌入式 HTTP 伺服器。
6.20.6. 配置嵌入式 Memcached 伺服器
在您的 Spring @PeerCacheApplication
或 @CacheServerApplication
類上使用 @EnableMemcachedServer
註解來啟動嵌入式 Memcached 伺服器(Gemcached),該伺服器監聽埠 11211
,如下所示
@SpringBootApplication
@CacheServerApplication
@EnableMemcachedServer
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
@EnableMemcachedServer 只能與 Apache Geode 伺服器應用程式一起使用。
|
請參閱 配置嵌入式 Memcached 伺服器 (Gemcached) 以獲取更多詳細資訊。
6.20.7. 配置嵌入式 Redis 伺服器
在您的 Spring @PeerCacheApplication
或 @CacheServerApplication
類上使用 @EnableRedisServer
註解來啟動嵌入式 Redis 伺服器,該伺服器監聽埠 6379
,如下所示
@SpringBootApplication
@CacheServerApplication
@EnableRedisServer
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
@EnableRedisServer 只能與 Apache Geode 伺服器應用程式一起使用。
|
您必須在 Spring [Boot] 應用程式類路徑上顯式宣告 org.apache.geode:geode-redis 模組。
|
請參閱 配置嵌入式 Redis 伺服器 以獲取更多詳細資訊。
6.20.8. 配置日誌記錄
要配置或調整 Apache Geode 日誌記錄,請在您的 Spring、Apache Geode 客戶端或伺服器應用程式類上使用 @EnableLogging
註解,如下所示
@SpringBootApplication
@ClientCacheApplication
@EnableLogging(logLevel="trace")
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
預設的 log-level 為“config”。此外,此註解不會調整應用程式中的日誌級別,僅適用於 Apache Geode。
|
請參閱 配置日誌記錄 以獲取更多詳細資訊。
6.20.9. 配置統計資訊
要在執行時收集 Apache Geode 統計資訊,請在您的 Spring、Apache Geode 客戶端或伺服器應用程式類上使用 @EnableStatistics
註解,如下所示
@SpringBootApplication
@ClientCacheApplication
@EnableStatistics
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
請參閱 配置統計資訊 以獲取更多詳細資訊。
6.20.10. 配置 PDX
要啟用 Apache Geode PDX 序列化,請在您的 Spring、Apache Geode 客戶端或伺服器應用程式類上使用 @EnablePdx
註解,如下所示
@SpringBootApplication
@ClientCacheApplication
@EnablePdx
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
Apache Geode PDX 序列化是 Java 序列化的替代方案,具有許多額外的好處。首先,它簡化了使所有應用程式域模型型別可序列化的過程,而無需實現 java.io.Serializable 。
|
預設情況下,SDG 會配置 MappingPdxSerializer 來序列化您的應用程式域模型型別,這不需要任何開箱即用的特殊配置來正確識別需要序列化的應用程式域物件,然後執行序列化,因為 MappingPdxSerializer 中的邏輯基於 Spring Data 的對映基礎設施。請參閱 MappingPdxSerializer 以獲取更多詳細資訊。
|
請參閱 @EnablePdx
Javadoc。
有關更多詳細資訊,請參閱 配置 PDX。
6.20.11. 配置 SSL
要啟用 Apache Geode SSL,請使用 @EnableSsl
註釋您的 Spring、Apache Geode 客戶端或伺服器應用程式類,如下所示
@SpringBootApplication
@ClientCacheApplication
@EnableSsl(components = SERVER)
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
至少,Apache Geode 要求您使用適當的配置屬性或屬性指定金鑰庫和信任庫。金鑰庫和信任庫配置屬性或屬性都可以引用同一個 KeyStore 檔案。此外,如果檔案已加密,您需要指定一個使用者名稱和密碼來訪問 KeyStore 檔案。
|
Apache Geode SSL 允許您配置系統中需要 TLS 的特定元件,例如客戶端/伺服器、定位器、閘道器等。可選地,您可以指定 Apache Geode 的所有元件都使用 SSL,方法是使用“ALL”。 |
請參閱 @EnableSsl
Javadoc。
有關更多詳細資訊,請參閱 配置 SSL。
6.20.12. 配置安全
要啟用 Apache Geode 安全,請使用 @EnableSecurity
註釋您的 Spring、Apache Geode 客戶端或伺服器應用程式類,如下所示
@SpringBootApplication
@ClientCacheApplication
@EnableSecurity
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
在伺服器上,您必須配置對身份驗證憑據的訪問。您可以實現 Apache Geode SecurityManager 介面,也可以宣告一個或多個 Apache Shiro Realms 。有關更多詳細資訊,請參閱 配置伺服器安全。
|
在客戶端上,您必須配置使用者名稱和密碼。有關更多詳細資訊,請參閱 配置客戶端安全。 |
有關更多詳細資訊,請參閱 配置安全。
6.20.13. 配置 Apache Geode 屬性
要配置其他未被面向功能的 SDG 配置註釋覆蓋的低階 Apache Geode 屬性,請使用 @GemFireProperties
註釋您的 Spring、Apache Geode 客戶端或伺服器應用程式類,如下所示
@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);
}
}
某些 Apache Geode 屬性僅在客戶端側,而其他屬性僅在伺服器側。請檢視 Apache Geode 文件,瞭解每個屬性的正確用法。 |
請參閱 配置 Apache Geode 屬性,瞭解更多詳細資訊。
6.20.14. 配置快取
要將 Apache Geode 用作 Spring 的 快取抽象 中的快取提供程式,並讓 SDG 自動為您的應用程式服務元件所需的快取建立 Apache Geode 區域,請使用 @EnableGemfireCaching
和 @EnableCachingDefinedRegions
註釋您的 Spring、Apache Geode 客戶端或伺服器應用程式類,如下所示
@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、Apache Geode 永續性客戶端或伺服器應用程式的過程,請使用 @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;
@Region("Books")
public class Book {
@Id
private ISBN isbn;
@Indexed;
private Author author;
@Indexed
private LocalDate published;
@LuceneIndexed
private String title;
}
最後,定義您的 CRUD 儲存庫,使用簡單的查詢來持久化和訪問 Books
,如下所示
package example.app.repo;
public interface BookRepository extends CrudRepository {
List<Book> findByAuthorOrderByPublishedDesc(Author author);
}
有關更多詳細資訊,請參閱 Apache Geode 儲存庫的 Spring Data。 |
請參閱 @Region
Javadoc。
請參閱 @Indexed
Javadoc。
有關更多詳細資訊,請參閱 配置區域。
有關更多詳細資訊,請參閱 Apache Geode 儲存庫的 Spring Data。
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. 配置函式
Apache Geode 函式在分散式計算場景中很有用,在這些場景中,可能需要大量計算才能在叢集中的節點上並行執行需要資料的計算。在這種情況下,將邏輯帶到資料所在的位置(儲存)比請求和獲取資料以供計算處理更有效。
使用 @EnableGemfireFunctions
以及 @GemfireFunction
註解來啟用作為 POJO 上方法實現的 Apache Geode 函式定義,如下所示
@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. 配置持續查詢
即時事件流處理正成為資料密集型應用程式越來越重要的任務,主要目的是及時響應使用者請求。Apache Geode 持續查詢 (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
方法。
Apache Geode CQ 僅是客戶端功能。 |
6.20.19. 配置叢集配置
在使用 Apache Geode 作為 Apache Geode ClientCache
應用程式開發 Spring Data 應用程式時,在開發過程中將伺服器配置為與客戶端在客戶端/伺服器拓撲中匹配非常有用。實際上,Apache Geode 預計當您在客戶端上擁有一個 "/Example" PROXY Region
時,伺服器中存在一個名稱匹配的 Region
(即 "Example")。
您可以使用 Gfsh 建立應用程式所需的每個 Region 和索引,或者,您只需在執行 Spring Data 應用程式使用 Apache Geode 時,將開發應用程式時已表達的配置元資料推送到伺服器即可。
這與使用 @EnableClusterConfiguration(..)
註釋您的主應用程式類一樣簡單
@EnableClusterConfiguration
@ClientCacheApplication
@EnableClusterConfiguration(useHttp = true)
class ClientApplication {
...
}
大多數情況下,在使用客戶端/伺服器拓撲結構時,特別是在生產環境中,叢集的伺服器將使用Gfsh啟動。在這種情況下,通常使用 HTTP(S) 將配置元資料(例如區域和索引定義)傳送到叢集。當使用 HTTP 時,配置元資料將傳送到叢集中的管理器,並在叢集中的伺服器節點之間一致地分發。 |
為了使用@EnableClusterConfiguration ,您必須在 Spring 應用程式類路徑中宣告org.springframework:spring-web 依賴項。
|
有關更多詳細資訊,請參閱配置叢集配置推送。
6.20.20. 配置GatewayReceivers
不同 Apache Geode 叢集之間的資料複製是一種越來越重要的容錯和高可用性 (HA) 機制。Apache Geode WAN 複製是一種機制,允許一個 Apache Geode 叢集以可靠且容錯的方式將其資料複製到另一個 Apache Geode 叢集。
Apache Geode WAN 複製需要配置兩個元件
-
GatewayReceiver
- 從遠端 Apache Geode 叢集的GatewaySender
接收資料的 WAN 複製元件。 -
GatewaySender
- 將資料傳送到遠端 Apache Geode 叢集的GatewayReceiver
的 WAN 複製元件。
要啟用GatewayReceiver
,應用程式類需要使用@EnableGatewayReceiver
進行註釋,如下所示
@CacheServerApplication
@EnableGatewayReceiver(manualStart = false, startPort = 10000, endPort = 11000, maximumTimeBetweenPings = 1000,
socketBufferSize = 16384, bindAddress = "localhost",transportFilters = {"transportBean1", "transportBean2"},
hostnameForSenders = "hostnameLocalhost"){
...
...
}
}
class MySpringApplication { .. }
Apache Geode 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 { .. }
}
Apache Geode GatewaySender 僅是伺服器端功能,只能在CacheServer 或對等Cache 節點上配置。
|
在上面的示例中,應用程式配置了 2 個區域,Region1
和Region2
。此外,將配置兩個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 (s) 將自動附加到應用程式中配置的每個Region 。
|
7. 使用 Apache Geode API
一旦 Apache Geode 快取和區域配置完成,它們就可以被注入並在應用程式物件中使用。本章描述了與 Spring 事務管理功能和 DAO 異常層次結構的整合。本章還涵蓋了對 Apache Geode 管理物件的依賴注入的支援。
7.1. GemfireTemplate
與 Spring 提供的許多其他高階抽象一樣,Spring Data for Apache Geode 提供了一個模板來簡化 Apache Geode 資料訪問操作。該類提供了包含常見區域操作的幾種方法,但也提供了使用GemfireCallback
對原生 Apache Geode API 執行程式碼的能力,而無需處理 Apache Geode 檢查異常。
模板類需要一個 Apache Geode Region
,並且一旦配置完成,它就是執行緒安全的,可以在多個應用程式類中重複使用。
<bean id="gemfireTemplate" class="org.springframework.data.gemfire.GemfireTemplate" p:region-ref="SomeRegion"/>
一旦模板配置完成,開發人員就可以將它與GemfireCallback
一起使用,直接與 Apache Geode 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");
}
});
為了訪問 Apache Geode 查詢語言的全部功能,開發人員可以使用find
和findUnique
方法,與query
方法相比,它們可以跨多個區域執行查詢、執行投影等等。
當查詢選擇多個專案(透過SelectResults
)時,應使用find
方法,而當僅返回一個物件時,應使用findUnique
方法,顧名思義。
7.2. 異常轉換
使用新的資料訪問技術不僅需要適應新的 API,還需要處理特定於該技術的異常。
為了適應異常處理情況,Spring 框架提供了一個與技術無關且一致的異常層次結構,它將應用程式從專有且通常是“檢查”的異常抽象到一組集中的執行時異常。
如Spring 框架文件中所述,異常轉換可以透過使用@Repository
註釋和 AOP 透明地應用於您的資料訪問物件 (DAO),方法是定義一個PersistenceExceptionTranslationPostProcessor
bean。只要聲明瞭CacheFactoryBean
(例如,使用<gfe:cache/>
或<gfe:client-cache>
宣告),使用 Apache Geode 時就會啟用相同的異常轉換功能,它充當異常轉換器,並由 Spring 基礎設施自動檢測並相應地使用。
7.3. 本地快取事務管理
Spring 框架最受歡迎的功能之一是事務管理。
如果您不熟悉 Spring 的事務抽象,那麼我們強烈建議您閱讀有關Spring 事務管理基礎設施的資訊,因為它提供了一個一致的程式設計模型,該模型在多個 API 上透明地工作,並且可以透過程式設計方式或宣告方式(最受歡迎的選擇)進行配置。
對於 Apache Geode,Spring Data for Apache Geode 提供了一個專用的、針對每個快取的 PlatformTransactionManager
,一旦宣告,就可以透過 Spring 原子地執行 Region 操作。
<gfe:transaction-manager id="txManager" cache-ref="myCache"/>
如果 Apache Geode 快取是在預設名稱 gemfireCache 下定義的,則上面的示例可以透過消除 cache-ref 屬性來進一步簡化。與其他 Spring Data for Apache Geode 名稱空間元素一樣,如果快取 bean 名稱未配置,則將使用上述命名約定。此外,如果未顯式指定,事務管理器名稱為“gemfireTransactionManager”。
|
目前,Apache Geode 支援具有 **讀已提交** 隔離級別的樂觀事務。此外,為了保證這種隔離級別,開發人員應避免進行手動修改快取中值的 **就地** 更改。為了防止這種情況發生,事務管理器預設情況下將快取配置為使用 **複製到讀取** 語義,這意味著每次執行讀取操作時都會建立實際值的克隆。如果需要,可以透過 copyOnRead
屬性停用此行為。
由於在啟用 **複製到讀取** 時會為給定鍵的值製作副本,因此您必須隨後呼叫 Region.put(key, value)
才能以事務方式更新該值。
有關底層 Geode 事務管理器的語義和行為的更多資訊,請參閱 Geode CacheTransactionManager Javadoc 以及 文件。
7.4. 全域性 JTA 事務管理
Apache Geode 也可以參與全域性 JTA 基於事務,例如由 Java EE 應用伺服器(例如 WebSphere Application Server (WAS))使用容器管理事務 (CMT) 以及其他 JTA 資源管理的事務。
但是,與許多其他 JTA “相容” 資源(例如 ActiveMQ 等 JMS 訊息代理)不同,Apache Geode **不是** XA 相容資源。因此,Apache Geode 必須在 JTA 事務(準備階段)中被定位為“最後一個資源”,因為它沒有實現兩階段提交協議,或者更確切地說,它不處理分散式事務。
許多能夠進行 CMT 的管理環境都支援 JTA 基於事務中的“最後一個資源”非 XA 相容資源,儘管 JTA 規範中實際上並不需要。有關非 XA 相容“最後一個資源”的更多資訊,請參閱 Red Hat 的 文件。事實上,Red Hat 的 JBoss 專案 Narayana 就是這樣一個 LGPL 開源實現。Narayana 將此稱為“最後一個資源提交最佳化”(LRCO)。更多詳細資訊可以在這裡找到 這裡。
無論您是在使用 Apache Geode 的獨立環境中,使用支援“Last Resource”的開源 JTA 事務管理實現,還是在受管環境(例如 WAS 等 Java EE AS)中,Spring Data for Apache Geode 都能滿足您的需求。
要將 Apache Geode 正確地用作涉及多個事務資源的 JTA 事務中的“Last Resource”,您必須完成一系列步驟。此外,此類安排中只能有一個非 XA 相容資源(例如 Apache Geode)。
1) 首先,您必須完成 Apache Geode 文件中的步驟 1-4 此處。
上面的步驟 #1 與您的 Spring [Boot] 和/或 [Data for Apache Geode] 應用程式無關,必須成功完成。 |
2) 參考 Apache Geode 文件中的步驟 5 此處,當使用 @EnableGemFireAsLastResource
註解時,Spring Data for Apache Geode 的註解支援將嘗試為您設定 GemFireCache
的 copyOnRead
屬性。
但是,如果 SDG 的自動配置在這方面不成功,那麼您必須在 <gfe:cache>
或 <gfe:client-cache>
XML 元素中顯式設定 copy-on-read
屬性,或者在 JavaConfig 中將 CacheFactoryBean
類的 copyOnRead
屬性設定為 true。例如
ClientCache
XML
<gfe:client-cache ... copy-on-read="true"/>
ClientCache
JavaConfig
@Bean
ClientCacheFactoryBean gemfireCache() {
ClientCacheFactoryBean gemfireCache = new ClientCacheFactoryBean();
gemfireCache.setCopyOnRead(true);
return gemfireCache;
}
對等 Cache
XML
<gfe:cache ... copy-on-read="true"/>
對等 Cache
JavaConfig
@Bean
CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setCopyOnRead(true);
return gemfireCache;
}
顯式設定 copy-on-read 屬性或 copyOnRead 屬性實際上沒有必要。啟用事務管理會處理讀取時的複製。
|
3) 在此階段,您跳過 Apache Geode 文件中的步驟 6-8 此處,並讓Spring Data Geode發揮其魔力。您只需使用 Spring Data for Apache Geode 的新 @EnableGemFireAsLastResource
註解來註解您的 Spring @Configuration
類,Spring 的 事務管理 基礎設施和 Spring Data for Apache Geode 的 @EnableGemFireAsLastResource
註解配置的組合即可完成此操作。
配置如下…
@Configuration
@EnableGemFireAsLastResource
@EnableTransactionManagement(order = 1)
class GeodeConfiguration {
...
}
唯一的要求是…
3.1) @EnableGemFireAsLastResource
註解必須宣告在與 Spring 的 @EnableTransactionManagement
註解相同的 Spring @Configuration
類上。
3.2) @EnableTransactionManagement
註解的 order
屬性必須顯式設定為非 Integer.MAX_VALUE
或 Integer.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 Apache Geode 的 GemfireTransactionManager 適用於“僅本地”快取事務,不適用於“全域性”JTA 事務。因此,在這種情況下,您不需要配置 SDG GemfireTransactionManager 。您需要配置 Spring 的 JtaTransactionManager ,如上所示。
|
有關使用Spring 的事務管理與 JTA 的更多詳細資訊,請參見 此處。
實際上,Spring Data for Apache Geode 的 @EnableGemFireAsLastResource
註解會匯入包含 2 個 Aspect Bean 定義的配置,這些定義在事務操作期間的適當點處理 Apache Geode 的 o.a.g.ra.GFConnectionFactory.getConnection()
和 o.a.g.ra.GFConnection.close()
操作。
具體來說,事件的正確順序如下
-
jtaTransation.begin()
-
GFConnectionFactory.getConnection()
-
呼叫應用程式的
@Transactional
服務方法 -
jtaTransaction.commit()
或jtaTransaction.rollback()
-
最後,
GFConnection.close()
這與您(作為應用程式開發人員)在必須自己使用 JTA API + Apache Geode API 時手動編寫程式碼的方式一致,如 Apache Geode 示例 中所示。
值得慶幸的是,Spring 為您完成了繁重的工作,您所需要做的就是在應用了適當的配置(如上所示)之後
@Service
class MyTransactionalService {
@Transactional
public <Return-Type> someTransactionalServiceMethod() {
// perform business logic interacting with and accessing multiple JTA resources atomically
}
...
}
上面的 #1 和 #4 由 Spring 的基於 JTA 的 PlatformTransactionManager
在您的應用程式進入 @Transactional
邊界時(即當呼叫 MyTransactionService.someTransactionalServiceMethod()
時)為您適當地處理。
#2 和 #3 由 Spring Data for Apache Geode 的使用 @EnableGemFireAsLastResource
註解啟用的新 Aspect 處理。
當然,#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 [...]]
有關使用 Apache Geode 快取級事務的更多詳細資訊,請參見 此處。
有關在 JTA 事務中使用 Apache Geode 的更多詳細資訊,請參見 此處。
有關將 Apache Geode 配置為“最後資源”的更多詳細資訊,請參見 此處。
7.5. 使用 @TransactionalEventListener
在使用事務時,可能需要註冊一個監聽器,以便在事務提交之前或之後,或在回滾發生後執行某些操作。
Spring Data for Apache Geode 使得建立監聽器變得容易,這些監聽器將在使用@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 MyApplicationEvent(...));
}
...
}
@TransactionalEventListener
註釋允許您指定事件處理程式方法將被呼叫的事務phase
。選項包括:AFTER_COMMIT
、AFTER_COMPLETION
、AFTER_ROLLBACK
和 BEFORE_COMMIT
。如果未指定,phase
預設值為 AFTER_COMMIT
。如果您希望即使在沒有事務的情況下也呼叫監聽器,您可以將fallbackExecution
設定為 true
。
7.6. 自動事務事件釋出
從 Spring Data for Apache Geode Neumann/2.3
開始,現在可以啟用自動事務事件釋出。
使用@EnableGemfireCacheTransactions
註釋,將enableAutoTransactionEventPublishing
屬性設定為 true。預設值為 false。
@EnableGemfireCacheTransactions(enableAutoTransactionEventPublishing = true)
class GeodeConfiguration { ... }
然後,您可以建立@TransactionalEventListener
註釋的 POJO 方法來處理AFTER_COMMIT
或 AFTER_ROLLBACK
事務階段的事務事件。
@Component
class TransactionEventListeners {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(TransactionApplicationEvent event) {
...
}
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleAfterRollback(TransactionApplicationEvent event) {
...
}
}
僅支援TransactionPhase.AFTER_COMMIT 和 TransactionPhase.AFTER_ROLLBACK 。不支援 TransactionPhase.BEFORE_COMMIT ,因為 1) SDG 採用 Apache Geode 的 TransactionListener 和 TransactionWriter 介面來實現自動事務事件釋出,以及 2) 當 Apache Geode 的 TransactionWriter.beforeCommit(:TransactionEvent) 被呼叫時,它已經在 AbstractPlatformTransactionManager.triggerBeforeCommit(:TransactionStatus) 呼叫之後,在該呼叫中,@TranactionalEventListener 註釋的 POJO 方法在事務生命週期中被呼叫。
|
使用自動事務事件釋出,您不需要在應用程式@Transactional
@Service
方法中顯式呼叫applicationEventPublisher.publishEvent(..)
方法。
但是,如果您仍然希望在“提交之前”接收事務事件,那麼您仍然必須在應用程式@Transactional
@Service
方法中呼叫applicationEventPublisher.publishEvent(..)
方法。有關更多詳細資訊,請參見上面的注意。
7.7. 連續查詢 (CQ)
Apache Geode 提供的一個強大功能是 連續查詢 (或 CQ)。
簡而言之,CQ 允許開發人員建立和註冊一個 OQL 查詢,然後在新增到 Apache Geode 的新資料與查詢謂詞匹配時自動收到通知。Spring Data for Apache Geode 透過org.springframework.data.gemfire.listener
包及其監聽器容器提供對 CQ 的專用支援;在功能和命名方面與Spring 框架中的 JMS 整合非常相似;事實上,熟悉 Spring 中 JMS 支援的使用者應該會感到賓至如歸。
基本上,Spring Data for Apache Geode 允許 POJO 上的方法成為 CQ 的端點。只需定義查詢並指定應在匹配時呼叫以接收通知的方法。Spring Data for Apache Geode 會處理其餘事宜。這與 Java EE 的訊息驅動 Bean 風格非常相似,但無需任何基於 Apache Geode 的基類或介面實現。
目前,持續查詢僅在 Apache Geode 的客戶端/伺服器拓撲中受支援。此外,使用的客戶端池需要啟用訂閱。有關更多資訊,請參閱 Apache Geode 文件。 |
7.7.1. 持續查詢監聽器容器
Spring Data for Apache Geode 透過使用 SDG 的 ContinuousQueryListenerContainer
簡化了 CQ 事件的建立、註冊、生命週期和分發,該容器負責 CQ 周圍的基礎設施,併為使用者完成所有繁重的工作。熟悉 EJB 和 JMS 的使用者應該會發現這些概念很熟悉,因為它被設計得儘可能接近 Spring 框架 中提供的支援,以及其訊息驅動 POJO (MDP)。
SDG ContinuousQueryListenerContainer
充當事件(或訊息)監聽器容器;它用於接收來自已註冊 CQ 的事件,並呼叫注入到其中的 POJO。監聽器容器負責所有訊息接收的執行緒處理,並將訊息分發到監聽器進行處理。它充當 EDP(事件驅動 POJO)和事件提供者之間的中介,並負責 CQ 的建立和註冊(以接收事件)、資源獲取和釋放、異常轉換等。這使您作為應用程式開發人員能夠編寫與接收事件(並對其做出反應)相關的(可能很複雜)業務邏輯,並將樣板 Apache Geode 基礎設施問題委託給框架。
監聽器容器是完全可定製的。開發人員可以選擇使用 CQ 執行緒執行排程(同步傳遞),或者透過定義合適的 `java.util.concurrent.Executor`(或 Spring 的 `TaskExecutor`)使用新執行緒(來自現有池)來實現非同步方法。根據負載、監聽器數量或執行時環境,開發人員應該更改或調整執行器以更好地滿足其需求。特別是,在託管環境(例如應用程式伺服器)中,強烈建議選擇合適的 `TaskExecutor` 以利用其執行時。
7.7.2. `ContinuousQueryListener` 和 `ContinuousQueryListenerAdapter`
`ContinuousQueryListenerAdapter` 類是 Spring Data for Apache Geode CQ 支援的最終元件。簡而言之,該類允許您將幾乎 **任何** 實現類作為 EDP 公開,而無需太多限制。`ContinuousQueryListenerAdapter` 實現 `ContinuousQueryListener` 介面,這是一個簡單的監聽器介面,類似於 Apache Geode 的 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` 介面的實現 **沒有** 任何 Apache Geode 依賴項。它確實是一個 POJO,我們可以透過以下配置將其轉換為 EDP。
該類不必實現介面;介面僅用於更好地展示契約和實現之間的解耦。 |
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:gfe="https://www.springframework.org/schema/geode"
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/geode https://www.springframework.org/schema/geode/spring-geode.xsd
">
<gfe:client-cache/>
<gfe:pool subscription-enabled="true">
<gfe:server host="localhost" port="40404"/>
</gfe:pool>
<gfe:cq-listener-container>
<!-- default handle method -->
<gfe:listener ref="listener" query="SELECT * FROM /SomeRegion"/>
<gfe:listener ref="another-listener" query="SELECT * FROM /AnotherRegion" name="myQuery" method="handleQuery"/>
</gfe:cq-listener-container>
<bean id="listener" class="example.DefaultMessageDelegate"/>
<bean id="another-listener" class="example.DefaultMessageDelegate"/>
...
<beans>
上面的示例展示了監聽器可以具有的幾種不同形式;在最少的情況下,需要監聽器引用和實際查詢定義。但是,可以為生成的連續查詢指定一個名稱(用於監控),還可以指定方法的名稱(預設值為 `handleEvent`)。指定的方法可以具有各種引數型別,`EventDelegate` 介面列出了允許的型別。 |
上面的示例使用 Spring Data for Apache Geode 名稱空間來宣告事件監聽器容器並自動註冊監聽器。完整的 **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>
每次收到事件時,介面卡都會自動在 Apache Geode 事件和所需方法引數之間進行型別轉換。方法呼叫引起的任何異常都會被容器捕獲並處理(預設情況下,會記錄異常)。
7.8. 連線 `Declarable` 元件
Apache Geode XML 配置(通常稱為 `cache.xml`)允許將 **使用者** 物件宣告為配置的一部分。通常這些物件是 `CacheLoaders` 或 Apache Geode 支援的其他可插拔回調元件。使用原生 Apache Geode 配置,透過 XML 宣告的每個使用者型別都必須實現 `Declarable` 介面,該介面允許透過 `Properties` 例項將任意引數傳遞給宣告的類。
在本節中,我們將描述如何在使用 Spring 時配置這些可插拔元件,這些元件在 cache.xml
中定義,同時保持您的快取/區域配置在 cache.xml
中定義。這允許您的可插拔元件專注於應用程式邏輯,而不是 DataSources
或其他協作者的位置或建立。
但是,如果您要啟動一個全新專案,建議您直接在 Spring 中配置快取、區域和其他可插拔的 Apache Geode 元件。這避免了從本節中介紹的 Declarable
介面或基類繼承。
有關此方法的更多資訊,請參見以下側邊欄。
以下宣告(取自 Declarable
Javadoc)是使用 Spring 配置 Declarable
元件的示例。
<cache-loader>
<class-name>com.company.app.DBLoader</class-name>
<parameter name="URL">
<string>jdbc://12.34.56.78/mydb</string>
</parameter>
</cache-loader>
為了簡化解析、轉換引數和初始化物件的步驟,Spring Data for Apache Geode 提供了一個基類(WiringDeclarableSupport
),它允許透過 **模板** bean 定義來連線 Apache Geode 使用者物件,或者在缺少模板 bean 定義的情況下,透過 Spring IoC 容器進行自動連線。為了利用此功能,使用者物件需要擴充套件 WiringDeclarableSupport
,它會自動定位宣告的 BeanFactory
並在初始化過程中執行連線。
7.8.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 作為模板來連線 Apache Geode 建立的例項。對於 bean 名稱使用不同約定的情況,可以在 Apache Geode 配置中傳入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.8.2. 使用自動連線和註釋進行配置
預設情況下,如果找不到 bean 定義,WiringDeclarableSupport
將自動連線宣告的例項。這意味著,除非例項提供任何依賴注入元資料,否則容器將找到物件的 setter 並嘗試自動滿足這些依賴項。但是,開發人員也可以使用 JDK 5 註釋為自動連線過程提供更多資訊。
我們強烈建議閱讀 Spring 文件中專門針對章節,以獲取有關支援的註釋和啟用因素的更多資訊。 |
例如,上面的假設DBLoader
宣告可以透過以下方式注入 Spring 配置的DataSource
class DBLoader extends WiringDeclarableSupport implements CacheLoader {
// use annotations to 'mark' the needed dependencies
@javax.inject.Inject
private DataSource dataSource;
public Object load(LoaderHelper helper) { ... }
}
<cache-loader>
<class-name>com.company.app.DBLoader</class-name>
<!-- no need to declare any parameters since the class is auto-wired -->
</cache-loader>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
">
<!-- enable annotation processing -->
<context:annotation-config/>
</beans>
透過使用 JSR-330 註釋,CacheLoader
程式碼已簡化,因為DataSource
的位置和建立已外部化,使用者程式碼只關注載入過程。DataSource
可能是事務性的,延遲建立的,在多個物件之間共享的,或者從 JNDI 中檢索的。這些方面可以透過 Spring 容器輕鬆配置和更改,而無需觸及DBLoader
程式碼。
7.9. 對 Spring 快取抽象的支援
Spring Data for Apache Geode 提供了 Spring 快取抽象 的實現,將 Apache Geode 定位為 Spring 快取基礎設施中的快取提供者。
要使用 Apache Geode 作為支援實現,即 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/geode"
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/geode https://www.springframework.org/schema/geode/spring-geode.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”),即<gfe:cache> 沒有顯式 ID,則CacheManager bean 定義上的cache-ref 屬性不是必需的。
|
當GemfireCacheManager
(單例)bean 例項被宣告並且宣告式快取被啟用(在 XML 中使用<cache:annotation-driven/>
或在 JavaConfig 中使用 Spring 的@EnableCaching
註釋),Spring 快取註釋(例如@Cacheable
)標識將使用 Apache Geode 區域在記憶體中快取資料的“快取”。
這些快取(即區域)必須在使用它們的快取註解之前存在,否則會發生錯誤。
例如,假設您有一個客戶服務應用程式,其中包含一個執行快取的 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/geode"
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/geode https://www.springframework.org/schema/geode/spring-geode.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. 使用 Apache Geode 序列化
為了提高 Apache Geode 記憶體資料網格的整體效能,Apache Geode 支援一種專用的序列化協議,稱為 PDX,它比標準 Java 序列化更快,並提供更緊湊的結果,此外它還可以在各種語言平臺(Java、C++ 和 .NET)上透明地工作。
有關更多詳細資訊,請參閱PDX 序列化功能 和 PDX 序列化內部機制。
本章討論 Spring Data for Apache Geode 簡化和改進 Apache Geode 在 Java 中的自定義序列化的各種方法。
8.1. 連線反序列化例項
序列化物件通常具有瞬態資料。瞬態資料通常取決於系統或其在特定時間點所在的執行環境。例如,DataSource
是特定於環境的。序列化此類資訊毫無用處,甚至可能很危險,因為它特定於某個 VM 或機器。對於這種情況,Spring Data for Apache Geode 提供了一個特殊的 Instantiator
,它在反序列化期間為 Apache Geode 建立的每個新例項執行連線。
透過這種機制,您可以依賴 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
預設情況下會將自身註冊到 Apache Geode 序列化系統,並在 Apache Geode 在反序列化期間建立的所有 SomeDataSerializableClass
例項上執行連線。
8.2. 自動生成自定義 Instantiators
對於資料密集型應用程式,隨著資料的流入,每臺機器上可能會建立大量例項。Apache Geode 使用反射來建立新型別,但對於某些場景,這可能會證明是昂貴的。與往常一樣,最好進行效能分析以量化這是否屬實。對於這種情況,Spring Data for Apache Geode 允許自動生成 Instatiator
類,這些類例項化一個新型別(使用預設建構函式),而無需使用反射。以下示例展示瞭如何建立例項化器
<bean id="instantiatorFactory" class="org.springframework.data.gemfire.serialization.InstantiatorFactoryBean">
<property name="customTypes">
<map>
<entry key="org.pkg.CustomTypeA" value="1025"/>
<entry key="org.pkg.CustomTypeB" value="1026"/>
</map>
</property>
</bean>
前面的定義自動為兩個類(CustomTypeA
和 CustomTypeB
)生成兩個 Instantiators
,並在使用者 ID 1025
和 1026
下將它們註冊到 Apache Geode。這兩個 Instantiators
避免使用反射,並透過 Java 程式碼直接建立例項。
9. POJO 對映
本節涵蓋
9.1. 物件對映基礎
本節涵蓋 Spring Data 物件對映的基礎知識,包括物件建立、欄位和屬性訪問、可變性和不可變性。請注意,本節僅適用於不使用底層資料儲存的物件對映的 Spring Data 模組(如 JPA)。此外,請務必查閱特定於儲存的章節,瞭解特定於儲存的物件對映,例如索引、自定義列或欄位名稱等。
Spring Data 物件對映的核心職責是建立域物件的例項,並將儲存本機資料結構對映到這些例項上。這意味著我們需要兩個基本步驟
-
使用公開的建構函式之一建立例項。
-
例項填充,以實現所有公開的屬性。
9.1.1. 物件建立
Spring Data 會自動嘗試檢測持久實體的建構函式,以用於實現該型別物件。解析演算法的工作原理如下
-
如果存在一個用
@PersistenceCreator
註解的靜態工廠方法,則使用它。 -
如果存在一個建構函式,則使用它。
-
如果存在多個建構函式,並且只有一個用
@PersistenceCreator
註解,則使用它。 -
如果存在無引數建構函式,則使用它。其他建構函式將被忽略。
值解析假設建構函式/工廠方法引數名稱與實體的屬性名稱匹配,即解析將像填充屬性一樣執行,包括對映中的所有自定義(不同的資料儲存列或欄位名稱等)。這也需要在類檔案中提供引數名稱資訊,或者在建構函式上存在@ConstructorProperties
註解。
可以使用 Spring Framework 的@Value
值註解使用特定於儲存的 SpEL 表示式來自定義值解析。有關更多詳細資訊,請參閱特定於儲存的對映部分。
9.1.2. 屬性填充
一旦建立了實體例項,Spring Data 將填充該類所有剩餘的持久屬性。除非實體的建構函式已經填充(即透過其建構函式引數列表使用),否則將首先填充識別符號屬性,以允許解析迴圈物件引用。之後,所有非瞬態屬性(尚未由建構函式填充)都將設定在實體例項上。為此,我們使用以下演算法
-
如果屬性是不可變的,但公開了一個
with…
方法(見下文),我們將使用with…
方法建立一個具有新屬性值的新實體例項。 -
如果定義了屬性訪問(即透過 getter 和 setter 訪問),我們將呼叫 setter 方法。
-
如果屬性是可變的,我們直接設定欄位。
-
如果屬性是不可變的,我們使用建構函式,該建構函式將被持久化操作使用(參見 物件建立)來建立例項的副本。
-
預設情況下,我們直接設定欄位值。
讓我們看一下以下實體。
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 | 識別符號屬性是最終的,但在建構函式中設定為 `null`。該類公開了一個 `withId(…)` 方法,用於設定識別符號,例如,當例項被插入到資料儲存中並且生成了識別符號時。原始的 `Person` 例項保持不變,因為建立了一個新的例項。相同的模式通常應用於其他儲存管理的屬性,但可能需要為持久化操作進行更改。with 方法是可選的,因為持久化建構函式(參見 6)實際上是一個複製建構函式,設定屬性將轉換為建立具有應用的新識別符號值的全新例項。 |
2 | `firstname` 和 `lastname` 屬性是普通的不可變屬性,可能透過 getter 公開。 |
3 | age 屬性是不可變的,但它是從 birthday 屬性派生的。在所示的設計中,資料庫值將勝過預設值,因為 Spring Data 使用唯一宣告的建構函式。即使意圖是優先考慮計算,但重要的是,此建構函式也應將 age 作為引數(以可能忽略它),否則屬性填充步驟將嘗試設定 age 欄位並由於它是不可變的並且沒有 with… 方法而失敗。 |
4 | comment 屬性是可變的,透過直接設定其欄位來填充。 |
5 | remarks 屬性是可變的,透過呼叫 setter 方法來填充。 |
6 | 該類公開了一個工廠方法和一個建構函式來建立物件。這裡的主要思想是使用工廠方法而不是額外的建構函式,以避免透過 @PersistenceCreator 進行建構函式歧義。相反,屬性的預設值在工廠方法中處理。如果希望 Spring Data 使用工廠方法進行物件例項化,請使用 @PersistenceCreator 對其進行註釋。 |
9.1.3. 一般建議
-
嘗試堅持使用不可變物件 — 不可變物件易於建立,因為實現物件只需呼叫其建構函式即可。此外,這避免了您的域物件充斥著 setter 方法,這些方法允許客戶端程式碼操作物件狀態。如果您需要這些方法,請優先將其設為包保護,以便它們只能被有限數量的同位型別呼叫。僅建構函式實現比屬性填充快 30%。
-
提供一個全引數建構函式 — 即使您不能或不想將您的實體建模為不可變值,提供一個將實體的所有屬性(包括可變屬性)作為引數的建構函式仍然有價值,因為這允許物件對映跳過屬性填充以實現最佳效能。
-
使用工廠方法而不是過載建構函式來避免
@PersistenceCreator
— 由於需要全引數建構函式來實現最佳效能,我們通常希望公開更多特定於應用程式用例的建構函式,這些建構函式省略了諸如自動生成的識別符號等內容。使用靜態工廠方法來公開這些全引數建構函式的變體是一種既定的模式。 -
確保您遵守允許使用生成的例項化器和屬性訪問器類的約束 —
-
對於要生成的識別符號,仍然使用最終欄位與全引數持久化建構函式(首選)或
with…
方法結合使用 — -
使用 Lombok 避免樣板程式碼 — 由於持久化操作通常需要一個包含所有引數的建構函式,它們的宣告變成了對樣板引數到欄位賦值的乏味重複,而 Lombok 的
@AllArgsConstructor
可以最好地避免這種情況。
覆蓋屬性
Java 允許靈活設計域類,其中子類可以定義一個與其超類中已宣告的同名屬性。考慮以下示例
public class SuperType {
private CharSequence field;
public SuperType(CharSequence field) {
this.field = field;
}
public CharSequence getField() {
return this.field;
}
public void setField(CharSequence field) {
this.field = field;
}
}
public class SubType extends SuperType {
private String field;
public SubType(String field) {
super(field);
this.field = field;
}
@Override
public String getField() {
return this.field;
}
public void setField(String field) {
this.field = field;
// optional
super.setField(field);
}
}
這兩個類都使用可賦值型別定義了一個 field
。然而,SubType
隱藏了 SuperType.field
。根據類設計,使用建構函式可能是設定 SuperType.field
的唯一預設方法。或者,在 setter 中呼叫 super.setField(…)
可以設定 SuperType
中的 field
。所有這些機制在某種程度上都會產生衝突,因為屬性具有相同的名稱,但可能代表兩個不同的值。如果型別不可賦值,Spring Data 會跳過超型別屬性。也就是說,覆蓋屬性的型別必須可賦值給其超型別屬性型別才能被註冊為覆蓋,否則超型別屬性將被視為瞬態。我們通常建議使用不同的屬性名稱。
Spring Data 模組通常支援包含不同值的覆蓋屬性。從程式設計模型的角度來看,需要考慮以下幾點
-
應該持久化哪個屬性(預設情況下為所有宣告的屬性)?您可以透過使用
@Transient
註解來排除屬性。 -
如何在資料儲存中表示屬性?對不同值使用相同的欄位/列名通常會導致資料損壞,因此您應該使用顯式欄位/列名對至少一個屬性進行註解。
-
無法使用
@AccessType(PROPERTY)
,因為在不進行任何關於 setter 實現的進一步假設的情況下,無法普遍設定超屬性。
9.1.4. Kotlin 支援
Spring Data 調整了 Kotlin 的具體細節,以允許物件建立和變異。
Kotlin 物件建立
支援例項化 Kotlin 類,所有類預設情況下都是不可變的,並且需要顯式屬性宣告來定義可變屬性。考慮以下 data
類 Person
data class Person(val id: String, val name: String)
上面的類編譯成一個具有顯式建構函式的典型類。我們可以透過新增另一個建構函式並使用 @PersistenceCreator
註解它來定製此類,以指示建構函式的優先順序
data class Person(var id: String, val name: String) {
@PersistenceCreator
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 中,所有類預設情況下都是不可變的,並且需要顯式屬性宣告來定義可變屬性。考慮以下 data
類 Person
data class Person(val id: String, val name: String)
此類實際上是不可變的。它允許建立新例項,因為 Kotlin 生成一個 copy(…)
方法,該方法建立新的物件例項,複製現有物件的所有屬性值,並應用作為方法引數提供的屬性值。
Kotlin 重寫屬性
Kotlin 允許宣告 屬性重寫 以更改子類中的屬性。
open class SuperType(open var field: Int)
class SubType(override var field: Int = 1) :
SuperType(field) {
}
這種安排會生成兩個名為 field
的屬性。Kotlin 為每個類中的每個屬性生成屬性訪問器(getter 和 setter)。實際上,程式碼看起來如下
public class SuperType {
private int field;
public SuperType(int field) {
this.field = field;
}
public int getField() {
return this.field;
}
public void setField(int field) {
this.field = field;
}
}
public final class SubType extends SuperType {
private int field;
public SubType(int field) {
super(field);
this.field = field;
}
public int getField() {
return this.field;
}
public void setField(int field) {
this.field = field;
}
}
SubType
上的 getter 和 setter 僅設定 SubType.field
,而不是 SuperType.field
。在這種安排中,使用建構函式是設定 SuperType.field
的唯一預設方法。向 SubType
新增一個方法來透過 this.SuperType.field = …
設定 SuperType.field
是可能的,但這超出了支援的約定。屬性重寫會在一定程度上造成衝突,因為屬性共享相同的名稱,但可能代表兩個不同的值。我們通常建議使用不同的屬性名稱。
Spring Data 模組通常支援包含不同值的覆蓋屬性。從程式設計模型的角度來看,需要考慮以下幾點
-
應該持久化哪個屬性(預設情況下為所有宣告的屬性)?您可以透過使用
@Transient
註解來排除屬性。 -
如何在資料儲存中表示屬性?對不同值使用相同的欄位/列名通常會導致資料損壞,因此您應該使用顯式欄位/列名對至少一個屬性進行註解。
-
由於無法設定超屬性,因此無法使用
@AccessType(PROPERTY)
。
9.2. 實體對映
Spring Data for Apache Geode 提供了對對映儲存在 Region 中的實體的支援。對映元資料透過在應用程式域類上使用註釋來定義,如下面的示例所示
@Region("People")
public class Person {
@Id Long id;
String firstname;
String lastname;
@PersistenceConstructor
public Person(String firstname, String lastname) {
// …
}
…
}
@Region
註釋可用於自定義儲存 Person
類例項的 Region。@Id
註釋可用於註釋用作快取 Region 金鑰的屬性,標識 Region 條目。@PersistenceConstructor
註釋有助於區分多個可能可用的建構函式,這些建構函式接受引數並明確標記註釋為建構函式的建構函式,該建構函式用於構建實體。在沒有或只有一個建構函式的應用程式域類中,您可以省略註釋。
除了將實體儲存在頂級 Region 中之外,還可以將實體儲存在子 Region 中,如下面的示例所示
@Region("/Users/Admin")
public class Admin extends User {
…
}
@Region("/Users/Guest")
public class Guest extends User {
…
}
請確保使用 Apache Geode Region 的完整路徑,該路徑由 Spring Data for Apache Geode XML 名稱空間定義,使用 <*-region>
元素的 id
或 name
屬性。
9.2.1. 按 Region 型別對映實體
除了 @Region
註解之外,Spring Data for Apache Geode 還識別特定於型別的 Region 對映註解:@ClientRegion
、@LocalRegion
、@PartitionRegion
和 @ReplicateRegion
。
在功能上,這些註解在 SDG 對映基礎設施中與通用 @Region
註解的處理方式完全相同。但是,這些額外的對映註解在 Spring Data for Apache Geode 的註解配置模型中很有用。當與 Spring @Configuration
註解類上的 @EnableEntityDefinedRegions
配置註解結合使用時,可以在本地快取中生成 Region,無論應用程式是客戶端還是對等方。
這些註解可以讓您更具體地指定應用程式實體類應該對映到的 Region 型別,並且還會影響 Region 的資料管理策略(例如,分割槽(也稱為分片)與複製資料)。
使用這些特定於型別的 Region 對映註解與 SDG 註解配置模型,可以避免您在配置中顯式定義這些 Region。
9.3. 儲存庫對映
作為在實體類上使用 @Region
註解來指定儲存實體的 Region 的替代方法,您也可以在實體的 Repository
介面上指定 @Region
註解。有關更多詳細資訊,請參見 Spring Data for Apache Geode 儲存庫。
但是,假設您想將 Person
記錄儲存在多個 Apache Geode Region 中(例如,People
和 Customers
)。然後,您可以定義相應的 Repository
介面擴充套件,如下所示
@Region("People")
public interface PersonRepository extends GemfireRepository<Person, String> {
…
}
@Region("Customers")
public interface CustomerRepository extends GemfireRepository<Person, String> {
...
}
然後,使用每個儲存庫,您可以將實體儲存在多個 Apache Geode Region 中,如下面的示例所示
@Service
class CustomerService {
CustomerRepository customerRepo;
PersonRepository personRepo;
Customer update(Customer customer) {
customerRepo.save(customer);
personRepo.save(customer);
return customer;
}
您甚至可以將 update
服務方法包裝在 Spring 管理的事務中,無論是本地快取事務還是全域性事務。
9.4. MappingPdxSerializer
Spring Data for Apache Geode 提供了一個自定義的 PdxSerializer
實現,稱為 MappingPdxSerializer
,它使用 Spring Data 對映元資料來定製實體序列化。
序列化器還允許您透過使用 Spring Data 的 EntityInstantiator
抽象來定製實體例項化。預設情況下,序列化器使用 ReflectionEntityInstantiator
,它使用對映實體的持久化建構函式。持久化建構函式可以是預設建構函式、單個宣告的建構函式或顯式用 @PersistenceConstructor
註解的建構函式。
為了為建構函式引數提供引數,序列化器從提供的 PdxReader
中讀取具有命名建構函式引數的欄位,這些欄位透過使用 Spring 的 @Value
註解顯式標識,如下例所示
@Value
public class Person {
public Person(@Value("#root.thing") String firstName, @Value("bean") String lastName) {
…
}
}
以這種方式進行註解的實體類將從 PdxReader
中讀取“thing”欄位,並將其作為建構函式引數 firstname
的引數值傳遞。lastName
的值是一個名為“bean”的 Spring bean。
除了 EntityInstantiators
提供的自定義例項化邏輯和策略之外,MappingPdxSerializer
還提供了遠遠超出 Apache Geode 自身的 ReflectionBasedAutoSerializer
的功能。
雖然 Apache Geode 的 ReflectionBasedAutoSerializer
方便地使用 Java 反射來填充實體,並使用正則表示式來識別應由序列化器處理(序列化和反序列化)的型別,但它不像 MappingPdxSerializer
那樣可以執行以下操作
-
根據實體欄位或屬性名稱和型別註冊自定義
PdxSerializer
物件。 -
方便地識別 ID 屬性。
-
自動處理只讀屬性。
-
自動處理瞬態屬性。
-
允許以更健壯的方式進行型別過濾,以確保型別安全(例如,不限於僅使用正則表示式來表達型別)。
現在,我們將更詳細地探討 MappingPdxSerializer
的每個功能。
9.4.1. 自定義 PdxSerializer 註冊
MappingPdxSerializer
使您能夠根據實體的欄位或屬性名稱和型別註冊自定義 PdxSerializers
。
例如,假設您已定義一個實體型別來建模 User
,如下所示
package example.app.security.auth.model;
public class User {
private String name;
private Password password;
...
}
雖然使用者的姓名可能不需要任何特殊的邏輯來序列化值,但另一方面,序列化密碼可能需要額外的邏輯來處理該欄位或屬性的敏感性。
您可能希望在透過網路(客戶端和伺服器之間)傳送值時,除了 TLS 之外,還要保護密碼,並且您只想儲存加鹽的雜湊值。當使用 MappingPdxSerializer
時,您可以註冊一個自定義的 PdxSerializer
來處理使用者的密碼,如下所示
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
,如下面的示例所示
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 屬性
與 Apache Geode 的 ReflectionBasedAutoSerializer
一樣,SDG 的 MappingPdxSerializer
也能夠確定實體的識別符號。但是,MappingPdxSerializer
透過使用 Spring Data 的對映元資料來實現這一點,具體來說,是透過使用 Spring Data 的 @Id
註解來查詢被指定為識別符號的實體屬性。或者,任何名為“id”且未顯式使用 @Id
註解的欄位或屬性也被指定為實體的識別符號。
例如
class Customer {
@Id
Long id;
...
}
在這種情況下,Customer
的 id
欄位透過使用 PdxWriter.markIdentifierField(:String)
在 PDX 型別元資料中被標記為識別符號欄位,當在序列化期間呼叫 PdxSerializer.toData(..)
方法時。
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。這正是發生的情況,與 Apache Geode 自己的 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. 按類型別過濾
與 Apache Geode 的 ReflectionBasedAutoSerializer
類似,SDG 的 MappingPdxSerializer
允許您過濾序列化和反序列化的物件型別。
但是,與 Apache Geode 的 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
,這些 Predicates
過濾或排除以下包中的型別
-
java.*
-
com.gemstone.gemfire.*
-
org.apache.geode.*
-
org.springframework.*
此外,MappingPdxSerializer
在呼叫 PdxSerializer.toData(:Object, :PdxWriter)
時過濾 null
物件,在呼叫 PdxSerializer.fromData(:Class<?>, :PdxReader)
方法時過濾 null
類型別。
透過簡單地定義一個 Predicate
並將其新增到 MappingPdxSerializer
中,就像前面展示的那樣,很容易為其他類型別或整個包型別新增排除項。
MappingPdxSerializer.setExcludeTypeFilters(:Predicate<Class<?>>)
方法是累加的,這意味著它使用 Predicate.and(:Predicate<Class<?>>)
方法將您的應用程式定義的型別過濾器與上面指示的現有預定義型別過濾器 Predicates
組合起來。
但是,如果您想包含一個類型別(例如,java.security Principal
),而該類型別被排除型別過濾器隱式排除,請參閱 包含型別過濾。
包含型別過濾
如果您想顯式包含一個類型別,或覆蓋一個隱式排除應用程式所需類型別的類型別過濾器(例如,java.security.Principal
,它預設情況下被 MappingPdxSerializer
上的 java.*
包排除型別過濾器排除),那麼只需定義相應的 Predicate
並使用 MappingPdxSerializer.setIncludeTypeFilters(:Predicate<Class<?>>)
方法將其新增到序列化器中,如下所示
Predicate<Class<?>> principalTypeFilter =
type -> java.security.Principal.class.isAssignableFrom(type);
mappingPdxSerializer.setIncludeTypeFilters(principalTypeFilters);
同樣,MappingPdxSerializer.setIncludeTypeFilters(:Predicate<Class<?>>)
方法與 setExcludeTypeFilters(:Predicate<Class<?>>)
一樣,是累加的,因此使用 Predicate.or(:Predicate<Class<?>>)
組合任何傳遞的型別過濾器。這意味著您可以根據需要多次呼叫 setIncludeTypeFilters(:Predicate<Class<?>>)
。
當存在包含型別過濾器時,MappingPdxSerializer
會根據以下條件決定是否對某個類型別的例項進行序列化或反序列化:該類型別既未被隱式排除,又明確包含,或者兩者都返回 true。然後,該類型別的例項將被適當地序列化或反序列化。
例如,當一個型別過濾器 Predicate<Class<Principal>>
被明確註冊時,如前所述,它會取消對 java.*
包型別隱式排除型別過濾器的作用。
10. Spring Data for Apache Geode 倉庫
Spring Data for Apache Geode 支援使用 Spring Data 倉庫抽象,以便輕鬆地將實體持久化到 Apache Geode 中,並執行查詢。有關倉庫程式設計模型的總體介紹,請參閱 此處。
10.1. Spring XML 配置
要引導 Spring Data 倉庫,請使用 Spring Data for Apache Geode 資料名稱空間中的 <repositories/>
元素,如下例所示
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:gfe-data="https://www.springframework.org/schema/data/geode"
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/geode https://www.springframework.org/schema/data/geode/spring-data-geode.xsd
">
<gfe-data:repositories base-package="com.example.acme.repository"/>
</beans>
上述配置片段會在配置的基包下查詢介面,併為這些介面建立倉庫例項,這些例項由 SimpleGemFireRepository
支援。
除非您已將應用程式域類正確對映到配置的區域,否則引導過程將失敗。 |
10.2. Spring 基於 Java 的配置
或者,許多開發人員更喜歡使用 Spring 的 基於 Java 的容器配置。
使用這種方法,您可以透過使用 SDG 的 @EnableGemfireRepositories
註解來引導 Spring Data 倉庫,如下例所示
@EnableGemfireRepositories
引導 Spring Data for Apache Geode 倉庫@SpringBootApplication
@EnableGemfireRepositories(basePackages = "com.example.acme.repository")
class SpringDataApplication {
...
}
您可能更喜歡使用型別安全的 basePackageClasses
屬性,而不是使用 basePackages
屬性。basePackageClasses
允許您透過僅指定一個應用程式倉庫介面型別來指定包含所有應用程式倉庫類的包。考慮在每個包中建立一個特殊的無操作標記類或介面,除了標識此屬性引用的應用程式倉庫的位置之外,它沒有任何其他用途。
除了 basePackages
和 basePackageClasses
屬性之外,與 Spring 的 @ComponentScan
註解類似,@EnableGemfireRepositories
註解還提供基於 Spring 的 ComponentScan.Filter
型別的包含和排除過濾器。您可以使用 filterType
屬性根據不同的方面進行過濾,例如應用程式倉庫型別是否使用特定註解進行註釋,或者是否擴充套件特定類型別等等。有關更多詳細資訊,請參閱 FilterType
Javadoc。
@EnableGemfireRepositories
註解還允許您使用 namedQueriesLocation
屬性指定命名 OQL 查詢的位置,這些查詢位於 Java Properties
檔案中。屬性名稱必須與倉庫查詢方法的名稱匹配,屬性值是您希望在呼叫倉庫查詢方法時執行的 OQL 查詢。
如果您的應用程式需要一個或多個 自定義倉庫實現,則可以將 repositoryImplementationPostfix
屬性設定為備用值(預設為 Impl
)。此功能通常用於擴充套件 Spring Data 倉庫基礎設施來實現資料儲存(例如 SDG)未提供的功能。
在使用 Apache Geode 時,自定義儲存庫實現的一個例子是在執行聯接時。SDG 儲存庫不支援聯接。對於 Apache Geode 的 PARTITION
區域,聯接必須在共置的 PARTITION
區域上執行,因為 Apache Geode 不支援“分散式”聯接。此外,等值聯接 OQL 查詢必須在 Apache Geode 函式內執行。有關 Apache Geode *等值聯接查詢* 的更多詳細資訊,請參閱 此處。
SDG 的儲存庫基礎設施擴充套件的許多其他方面也可以自定義。有關所有配置設定的更多詳細資訊,請參閱 @EnableGemfireRepositories
Javadoc。
10.3. 執行 OQL 查詢
Spring Data for Apache Geode 儲存庫允許定義查詢方法,以輕鬆地對託管實體對映到的區域執行 Apache Geode OQL 查詢,如下面的示例所示
@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
註釋查詢方法,如第三和第四個方法所示。
下表提供了您可以用在查詢方法中的支援關鍵字的簡要示例
關鍵字 | 示例 | 邏輯結果 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(無關鍵字) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10.4. 使用註解的 OQL 查詢擴充套件
許多查詢語言,例如 Apache Geode 的 OQL(物件查詢語言),都有一些 Spring Data Commons 的 Repository 基礎設施不支援的擴充套件。
Spring Data Commons 的 Repository 基礎設施的目標之一是充當最低公分母,以維護對當今應用程式開發中使用最廣泛的各種資料儲存的支援和可移植性。從技術上講,這意味著開發人員可以透過重用其現有的特定於應用程式的 Repository 介面來訪問其應用程式中 Spring Data Commons 支援的多個不同資料儲存,這是一個方便且強大的抽象。
為了支援 Apache Geode 的 OQL 查詢語言擴充套件並保持跨不同資料儲存的可移植性,Spring Data for Apache Geode 透過使用 Java 註解添加了對 OQL 查詢擴充套件的支援。這些註解會被其他 Spring Data Repository 實現(例如 Spring Data JPA 或 Spring Data Redis)忽略,這些實現沒有類似的查詢語言功能。
例如,大多數資料儲存可能沒有實現 Apache Geode 的 OQL IMPORT
關鍵字。將 IMPORT
實現為註解(即 @Import
)而不是作為查詢方法簽名的一部分(具體來說,是方法“名稱”),不會在評估查詢方法名稱以構建另一個數據儲存語言適當的查詢時干擾解析基礎設施。
目前,Spring Data for Apache Geode 支援的 Apache Geode OQL 查詢語言擴充套件集包括
關鍵字 | 註解 | 描述 | 引數 |
---|---|---|---|
|
OQL 查詢索引提示 |
|
|
|
限定特定於應用程式的型別。 |
|
|
|
限制返回的查詢結果集。 |
|
|
|
啟用 OQL 查詢特定的除錯。 |
NA |
例如,假設您有一個名為 Customers
的應用程式域類和相應的 Apache Geode 區域,以及一個 CustomerRepository
和一個用於按姓氏查詢 Customers
的查詢方法,如下所示
package ...;
...
@Region("Customers")
public class Customer ... {
@Id
private Long id;
...
}
package ...;
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 Apache Geode 的儲存庫擴充套件謹慎地避免在使用 OQL 註釋擴充套件與 @Query
註釋結合使用時建立衝突的宣告。
再舉一個例子,假設您在 CustomerRepository
中定義了一個原始的 @Query
註釋的查詢方法,如下所示
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
註釋是多餘的,不會產生額外的影響。
|
10.5. 查詢後處理
由於使用了 Spring Data 儲存庫抽象,定義資料儲存特定查詢(例如 OQL)的查詢方法約定非常簡單方便。但是,有時您可能仍然希望檢查甚至修改從儲存庫查詢方法生成的查詢。
從 2.0.x 版本開始,Spring Data for Apache Geode 包含 o.s.d.gemfire.repository.query.QueryPostProcessor
函式介面。該介面的定義如下
package org.springframework.data.gemfire.repository.query;
@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
介面,這在多個 QueryPostProcessors
在 Spring 容器中宣告和註冊並用於為一組生成的查詢方法查詢建立處理管道時很有用。
最後,QueryPostProcessor
接受與型別引數 T
和 QUERY
分別對應的型別引數。型別 T
擴充套件了 Spring Data Commons 標記介面,org.springframework.data.repository.Repository
。我們將在本節後面進一步討論這一點。Spring Data for Apache Geode 中的所有 QUERY
型別引數都是 java.lang.String
型別。
將查詢定義為 QUERY 型別很有用,因為此 QueryPostProcessor 介面可能移植到 Spring Data Commons,因此必須處理不同資料儲存(如 JPA、MongoDB 或 Redis)的所有查詢形式。
|
您可以實現此介面以接收一個回撥,其中包含從應用程式 Repository
介面方法呼叫該方法時生成的查詢。
例如,您可能希望記錄來自所有應用程式 Repository 介面定義的所有查詢。您可以透過使用以下 QueryPostProcessor
實現來做到這一點
package example;
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
,如下例所示
interface CustomerRepository extends CrudRepository<Customer, Long> {
Customer findByAccountNumber(String accountNumber);
List<Customer> findByLastNameLike(String lastName);
}
然後,您可以將 LoggingQueryPostProcessor
特定型別化為 CustomerRepository
,如下所示
class LoggingQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> { .. }
因此,僅記錄在 CustomerRepository
介面中定義的查詢,例如 findByAccountNumber
。
您可能希望為 Repository 查詢方法定義的特定查詢建立一個 QueryPostProcessor
。例如,假設您希望將從 CustomerRepository.findByLastNameLike(:String)
查詢方法生成的 OQL 查詢限制為僅返回五個結果,並按 firstName
升序對 Customers
進行排序。為此,您可以定義一個自定義 QueryPostProcessor
,如下例所示
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 Apache Geode 提供的 Spring Data 儲存庫約定來實現相同的效果。例如,可以按如下方式定義相同的查詢
interface CustomerRepository extends CrudRepository<Customer, Long> {
@Limit(5)
List<Customer> findDistinctByLastNameLikeOrderByFirstNameDesc(String lastName);
}
但是,如果您無法控制應用程式 CustomerRepository
介面定義,那麼 QueryPostProcessor
(即 OrderedLimitedCustomerByLastNameQueryPostProcessor
)很方便。
如果您想確保 LoggingQueryPostProcessor
始終在其他可能已在 Spring ApplicationContext
中宣告和註冊的應用程式定義的 QueryPostProcessors
之後出現,您可以透過覆蓋 o.s.core.Ordered.getOrder()
方法來設定 order
屬性,如下例所示
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 Apache Geode 包含註解支援,以簡化使用 Apache Geode 函式執行 的工作。
在幕後,Apache Geode API 提供了類來實現和註冊 Apache Geode 函式,這些函式部署在 Apache Geode 伺服器上,然後可以由其他對等成員應用程式或從快取客戶端遠端呼叫。
函式可以在並行執行,分佈在叢集中的多個 Apache Geode 伺服器上,使用 map-reduce 模式聚合結果併發送回呼叫方。函式也可以被定位到單個伺服器或區域上。Apache Geode API 支援使用各種預定義範圍定位的函式的遠端執行:在區域上、在成員(在組中)上、在伺服器上以及其他範圍。與任何 RPC 協議一樣,遠端函式的實現和執行需要一些樣板程式碼。
Spring Data for Apache Geode 忠實於 Spring 的核心價值主張,旨在隱藏遠端函式執行的機制,讓您專注於核心 POJO 程式設計和業務邏輯。為此,Spring Data for Apache Geode 引入了註解,以宣告性地將 POJO 類的公共方法註冊為 Apache Geode 函式,以及透過使用帶註解的介面來呼叫註冊的函式(包括遠端呼叫)的能力。
11.1. 實現與執行
需要解決兩個獨立的問題:實現和執行。
首先是函式實現(伺服器端),它必須與 FunctionContext
互動以訪問呼叫引數,與 ResultsSender
互動以傳送結果,以及其他執行上下文資訊。函式實現通常訪問快取和區域,並在 FunctionService
中使用唯一 ID 註冊。
呼叫函式的快取客戶端應用程式不依賴於實現。為了呼叫函式,應用程式例項化一個 Execution
,提供函式 ID、呼叫引數和函式目標,該目標定義了其範圍:區域、伺服器、伺服器組、成員或成員組。如果函式產生結果,呼叫者使用 ResultCollector
來聚合和獲取執行結果。在某些情況下,需要自定義的 ResultCollector
實現,並可能在 Execution
中註冊。
“客戶端”和“伺服器”在此處用於函式執行的上下文中,可能與 Apache Geode 的客戶端-伺服器拓撲中的客戶端和伺服器具有不同的含義。雖然使用 ClientCache 例項的應用程式通常會在叢集中的一個或多個 Apache Geode 伺服器上呼叫函式,但也可以在對等(P2P)配置中執行函式,其中應用程式是託管對等 Cache 例項的叢集的成員。請記住,對等成員快取應用程式受作為叢集對等成員的所有約束。
|
11.2. 實現函式
使用 Apache Geode API,FunctionContext
提供了一個執行時呼叫上下文,其中包括客戶端的呼叫引數和一個 ResultSender
實現,用於將結果傳送回客戶端。此外,如果函式在區域上執行,FunctionContext
實際上是 RegionFunctionContext
的例項,它提供了更多資訊,例如呼叫函式的目標區域、與 Execution
關聯的任何過濾器(一組特定鍵)等等。如果區域是 PARTITION
區域,函式應使用 PartitionRegionHelper
來提取本地資料集。
透過使用 Spring,您可以編寫一個簡單的 POJO,並使用 Spring 容器將一個或多個 POJO 的公共方法繫結到一個 Function。用於作為 Function 的 POJO 方法的簽名通常必須符合客戶端的執行引數。但是,在 Region 執行的情況下,Region 資料也可能被提供(假設資料儲存在本地分割槽中,如果 Region 是一個 PARTITION
Region)。
此外,Function 可能需要應用的過濾器(如果有)。這表明客戶端和伺服器共享呼叫引數的契約,但方法簽名可能包含額外的引數來傳遞由 FunctionContext
提供的值。一種可能性是客戶端和伺服器共享一個公共介面,但這並不是嚴格要求的。唯一的約束是方法簽名包含與呼叫 Function 時使用的相同順序的呼叫引數,在解析額外的引數後。
例如,假設客戶端提供一個 String
和一個 int
作為呼叫引數。這些引數在 FunctionContext
中以陣列的形式提供,如下例所示
Object[] args = new Object[] { "test", 123 };
Spring 容器應該能夠繫結到任何類似於以下方法簽名(暫時忽略返回值型別)
public Object method1(String s1, int i2) { ... }
public Object method2(Map<?, ?> data, String s1, int i2) { ... }
public Object method3(String s1, Map<?, ?> data, int i2) { ... }
public Object method4(String s1, Map<?, ?> data, Set<?> filter, int i2) { ... }
public void method4(String s1, Set<?> filter, int i2, Region<?,?> data) { ... }
public void method5(String s1, ResultSender rs, int i2) { ... }
public void method6(FunctionContest context) { ... }
一般規則是,一旦解析了任何額外的引數(即 Region 資料和過濾器),剩餘的引數必須在順序和型別上完全對應於預期的 Function 方法引數。方法的返回值型別必須是 void 或可以序列化的型別(作為 java.io.Serializable
、DataSerializable
或 PdxSerializable
)。後者也是呼叫引數的要求。
Region 資料通常應該定義為一個 Map
,以方便單元測試,但如果需要,也可以是 Region 型別。如前面的示例所示,傳遞 FunctionContext
本身或 ResultSender
也是有效的,如果您需要控制結果如何返回給客戶端。
11.2.1. Function 實現的註解
以下示例展示瞭如何使用 SDG 的函式註解將 POJO 方法公開為 Apache Geode 函式。
@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,並且每個 Apache Geode 函式都用 @GemfireFunction
註解。在前面的示例中,使用了 Spring 的 @Component
註解,但您可以使用 Spring 支援的任何方法(例如 XML 配置或在使用 Spring Boot 時使用 Java 配置類)來註冊 bean。這使 Spring 容器能夠建立此類的例項並將其包裝在 PojoFunctionWrapper
中。Spring 為每個用 @GemfireFunction
註解的方法建立了一個包裝器例項。每個包裝器例項共享相同的目標物件例項來呼叫相應的方法。
POJO 函式類是 Spring bean 的事實可能會帶來其他好處。由於它與 Apache Geode 元件(例如快取和區域)共享 ApplicationContext ,因此如果需要,可以將這些元件注入到該類中。
|
Spring 建立包裝器類並將函式註冊到 Apache Geode 的 FunctionService
中。用於註冊每個函式的函式 ID 必須是唯一的。按照慣例,它預設為簡單(未限定)方法名稱。可以使用 @GemfireFunction
註解的 id
屬性顯式定義名稱。
@GemfireFunction
註解還提供其他配置屬性:HA
和 optimizedForWrite
,它們對應於 Apache Geode 的 Function
介面定義的屬性。
如果 POJO 函式方法的返回型別為 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
] 列舉值之一。最後,可選地,Key
是指定的目標區域中的有效鍵。
PojoFunctionWrapper
實現 Apache Geode 的 Function
介面,繫結方法引數,並在其 execute()
方法中呼叫目標方法。它還使用 ResultSender
將方法的返回值傳送回撥用者。
11.2.2. 批次結果
如果返回型別是陣列或 Collection
,則必須考慮如何返回結果。預設情況下,PojoFunctionWrapper
會一次性返回整個陣列或 Collection
。如果陣列或 Collection
中的元素數量很大,則可能會導致效能下降。為了將有效負載劃分為更小、更易於管理的塊,您可以設定 batchSize
屬性,如前面顯示的 function2
中所示。
如果您需要更多地控制 ResultSender ,特別是如果方法本身會使用太多記憶體來建立 Collection ,則可以傳入 ResultSender 或透過 FunctionContext 訪問它,並直接在方法中使用它將結果傳送回撥用者。
|
11.3. 執行函式
呼叫遠端函式的程序需要提供函式的 ID、呼叫引數、執行目標(onRegion
、onServers
、onServer
、onMember
或 onMembers
)以及(可選)過濾器集。透過使用 Spring Data for Apache Geode,您只需定義一個由註釋支援的介面。Spring 為該介面建立一個動態代理,該代理使用 FunctionService
建立一個 Execution
,呼叫 Execution
,並在必要時將結果強制轉換為定義的返回型別。此技術類似於 Spring Data for Apache Geode 的 Repository 擴充套件的工作方式。因此,某些配置和概念應該很熟悉。
通常,單個介面定義對映到多個函式執行,每個函式執行對應於介面中定義的每個方法。
11.3.1. 函式執行的註釋
為了支援客戶端函式執行,提供了以下 SDG 函式註釋:@OnRegion
、@OnServer
、@OnServers
、@OnMember
和 @OnMembers
。這些註釋對應於 Apache Geode 的 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 中啟用 Function 執行註解處理,請在您的 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. 程式設計方式的 Function 執行
使用上一節中定義的 Function 執行帶註解的介面,只需將您的介面自動裝配到將呼叫 Function 的應用程式 bean 中即可
@Component
public class MyApplication {
@Autowired
FunctionExecution functionExecution;
public void doSomething() {
functionExecution.doIt("hello", 123);
}
}
或者,您可以直接使用 Function 執行模板。在以下示例中,GemfireOnRegionFunctionTemplate
建立了一個 onRegion
Function Execution
GemfireOnRegionFunctionTemplate
Set<?, ?> myFilter = getFilter();
Region<?, ?> myRegion = getRegion();
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(myRegion);
String result = template.executeAndExtract("someFunction", myFilter, "hello", "world", 1234);
在內部,Function Executions
始終返回一個 List
。executeAndExtract
假設一個包含結果的單例 List
,並嘗試將該值強制轉換為請求的型別。還有一個 execute
方法按原樣返回 List
。第一個引數是 Function ID。過濾器引數是可選的。其餘引數是可變引數 List
。
11.5. 使用 PDX 的 Function 執行
在使用 Spring Data for Apache Geode 的 Function 註解支援與 Apache Geode 的 PDX 序列化 相結合時,需要牢記一些邏輯上的事項。
如本節前面所述,並以示例說明,您通常應該使用帶 Spring Data for Apache Geode Function 註解 的 POJO 類來定義 Apache Geode Function,如下所示
public class OrderFunctions {
@GemfireFunction(...)
Order process(@RegionData data, Order order, OrderSource orderSourceEnum, Integer count) { ... }
}
Integer 型別的 count 引數是任意的,Order 類和 OrderSource 列舉的劃分也是任意的,它們在邏輯上可以合併。但是,引數的設定方式是為了演示在 PDX 上下文中 Function 執行的問題。
|
您的 Order
類和 OrderSource
列舉可能定義如下
public class Order ... {
private Long orderNumber;
private LocalDateTime orderDateTime;
private Customer customer;
private List<Item> items
...
}
public enum OrderSource {
ONLINE,
PHONE,
POINT_OF_SALE
...
}
當然,您可以定義一個 Function `Execution` 介面來呼叫 'process' Apache Geode 伺服器 Function,如下所示
@OnServer
public interface OrderProcessingFunctions {
Order process(Order order, OrderSource orderSourceEnum, Integer count);
}
顯然,這個 `process(..)` `Order` Function 是從客戶端使用 `ClientCache` 例項(即 `
現在,如果您已將 Apache Geode 配置為使用 PDX 進行序列化(例如,而不是使用 Java 序列化),您也可以在 Apache Geode 伺服器的配置中將 `pdx-read-serialized` 屬性設定為 `true`,如下所示
<gfe:cache pdx-read-serialized="true"/>
或者,您可以將 `pdx-read-serialized` 屬性設定為 `true`,用於 Apache Geode 快取客戶端應用程式,如下所示
<gfe:client-cache pdx-read-serialized="true"/>
這樣做會導致從快取(即 Regions)讀取的所有值以及在客戶端和伺服器(或對等節點)之間傳遞的資訊保持序列化形式,包括但不限於 Function 引數。
Apache Geode 僅序列化您已明確配置(註冊)的應用程式域物件型別,方法是使用 Apache Geode 的 `ReflectionBasedAutoSerializer`,或專門(建議)使用“自定義”Apache Geode `PdxSerializer`。如果您使用 Spring Data for Apache Geode 的 Repository 擴充套件,您甚至可能想要考慮使用 Spring Data for Apache Geode 的 `MappingPdxSerializer`,它使用實體的對映元資料來確定從應用程式域物件中序列化到 PDX 例項的資料。
然而,不那麼明顯的是,Apache Geode 會自動處理 Java `Enum` 型別,無論它們是否被明確配置(即,使用 `ReflectionBasedAutoSerializer` 註冊,使用正則表示式模式和 `classes` 引數,或由“自定義”Apache Geode `PdxSerializer` 處理),儘管 Java 列舉實現了 `java.io.Serializable`。
因此,當您在註冊了 Apache Geode Function(包括 Spring Data for Apache Geode Function 註釋的 POJO 類)的 Apache Geode 伺服器上將 `pdx-read-serialized` 設定為 `true` 時,您可能會在呼叫 Function `Execution` 時遇到意外的行為。
在呼叫函式時,您可能會傳遞以下引數
orderProcessingFunctions.process(new Order(123, customer, LocalDateTime.now(), items), OrderSource.ONLINE, 400);
但是,伺服器上的 Apache Geode 函式會收到以下內容
process(regionData, order:PdxInstance, :PdxInstanceEnum, 400);
Order
和 OrderSource
已作為 PDX 例項 傳遞給函式。同樣,這一切都是因為 pdx-read-serialized
設定為 true
,這在 Apache Geode 伺服器與多個不同客戶端互動(例如,Java 客戶端和本機客戶端,如 C/C++、C# 等)的情況下可能是必要的。
這與 Spring Data for Apache Geode 的強型別函式註釋 POJO 類方法簽名相沖突,在這些簽名中,您會合理地期望應用程式域物件型別而不是 PDX 序列化例項。
因此,Spring Data for Apache Geode 包含增強的函式支援,以自動將 PDX 型別的方法引數轉換為函式方法簽名(引數型別)定義的所需應用程式域物件型別。
但是,這也要求您在註冊和使用 Spring Data for Apache Geode 函式註釋 POJO 的 Apache Geode 伺服器上顯式註冊 Apache Geode PdxSerializer
,如下例所示
<bean id="customPdxSerializer" class="x.y.z.gemfire.serialization.pdx.MyCustomPdxSerializer"/>
<gfe:cache pdx-serializer-ref="customPdxSerializeer" pdx-read-serialized="true"/>
或者,您可以使用 Apache Geode 的 ReflectionBasedAutoSerializer
以方便起見。當然,我們建議您儘可能使用自定義 PdxSerializer
來維護對序列化策略的更細粒度控制。
最後,Spring Data for Apache Geode 謹慎地不會轉換您的函式引數,如果您以通用方式或作為 Apache Geode 的 PDX 型別之一來處理您的函式引數,如下所示
@GemfireFunction
public Object genericFunction(String value, Object domainObject, PdxInstanceEnum pdxEnum) {
// ...
}
Spring Data for Apache Geode 僅當相應的應用程式域型別在類路徑上且函式註釋 POJO 方法期望它時,才會將 PDX 型別的資料轉換為相應的應用程式域型別。
有關自定義、組合的應用程式特定 Apache Geode PdxSerializers
以及基於方法簽名的適當 POJO 函式引數型別處理的良好示例,請參閱 Spring Data for Apache Geode 的 ClientCacheFunctionExecutionWithPdxIntegrationTest
類。
12. Apache Lucene 整合
Apache Geode 整合 Apache Lucene,允許您使用 Lucene 查詢對儲存在 Apache Geode 中的資料進行索引和搜尋。基於搜尋的查詢還包括分頁查詢結果的功能。
此外,Spring Data for Apache Geode 添加了對基於 Spring Data Commons 投影基礎設施的查詢投影的支援。此功能允許根據應用程式的需要將查詢結果投影到一流的應用程式域型別中。
在執行任何基於 Lucene 搜尋的查詢之前,必須建立 Lucene Index
。可以在 Spring(Data for Apache Geode)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 Apache Geode 的 LuceneIndexFactoryBean
API 和 SDG 的 XML 名稱空間還允許在建立 LuceneIndex
時指定 org.apache.geode.cache.lucene.LuceneSerializer
。LuceneSerializer
允許您配置在對物件進行索引時將物件轉換為 Lucene 文件的方式。
以下示例顯示瞭如何將 LuceneSerializer
新增到 LuceneIndex
<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();
}
Apache Geode 的 Apache Lucene 整合和支援存在一些限制。
首先,只能在 Apache Geode PARTITION
區域上建立 LuceneIndex
。
其次,所有 LuceneIndexes
必須在應用 LuceneIndex
的區域之前建立。
為了幫助確保在 Spring 容器中定義的所有宣告的 LuceneIndexes 都在它們所應用的區域之前建立,SDG 包含 org.springframework.data.gemfire.config.support.LuceneIndexRegionBeanFactoryPostProcessor 。您可以使用 <bean class="org.springframework.data.gemfire.config.support.LuceneIndexRegionBeanFactoryPostProcessor"/> 在 XML 配置中註冊此 Spring BeanFactoryPostProcessor 。o.s.d.g.config.support.LuceneIndexRegionBeanFactoryPostProcessor 只能在使用 SDG XML 配置時使用。有關 Spring 的 BeanFactoryPostProcessors 的更多詳細資訊,請參閱 此處。
|
這些 Apache Geode 限制可能不會在將來的版本中適用,這就是為什麼 SDG LuceneIndexFactoryBean
API 直接引用區域,而不僅僅是區域路徑的原因。
當您希望在應用程式生命週期的後期階段,根據需求在現有包含資料的 Region 上定義 LuceneIndex
時,這種方法更理想。在可能的情況下,SDG 努力堅持使用強型別物件。但是,目前,您必須使用 regionPath
屬性來指定應用 LuceneIndex
的 Region。
此外,在前面的示例中,請注意 Books Region bean 定義上存在 Spring 的 @DependsOn 註解。這在 Books Region bean 和 bookTitleIndex LuceneIndex bean 定義之間建立了一個依賴關係,確保在應用 LuceneIndex 的 Region 之前建立 LuceneIndex 。
|
現在,一旦我們有了 LuceneIndex
,就可以執行基於 Lucene 的資料訪問操作,例如查詢。
12.1. Lucene 模板資料訪問器
Spring Data for Apache Geode 提供了兩種主要模板用於 Lucene 資料訪問操作,具體取決於您的應用程式準備處理的級別。
LuceneOperations
介面使用 Apache Geode 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
介面中的操作與 Apache Geode 的 LuceneQuery 介面提供的操作相匹配。但是,SDG 具有將專有的 Apache Geode 或 Apache Lucene Exceptions
轉換為 Spring 高度一致且表達力強的 DAO 異常層次結構 的附加值,特別是因為許多現代資料訪問操作涉及多個儲存或儲存庫。
此外,SDG 的 LuceneOperations
介面可以保護您的應用程式免受底層 Apache Geode 或 Apache Lucene API 在發生時引入的介面破壞性更改。
但是,提供一個僅使用 Apache Geode 和 Apache Lucene 資料型別(例如 Apache Geode 的 LuceneResultStruct
)的 Lucene 資料訪問物件 (DAO) 會很遺憾。因此,SDG 為您提供了 ProjectingLuceneOperations
介面來解決這些重要的應用程式問題。以下清單顯示了 ProjectingLuceneOperations
介面定義
public interface ProjectingLuceneOperations {
<T> List<T> query(String query, String defaultField [, int resultLimit], Class<T> projectionType);
<T> Page<T> query(String query, String defaultField, int resultLimit, int pageSize, Class<T> projectionType);
<T> List<T> query(LuceneQueryProvider queryProvider [, int resultLimit], Class<T> projectionType);
<T> Page<T> query(LuceneQueryProvider queryProvider, int resultLimit, int pageSize, Class<T> projectionType);
}
ProjectingLuceneOperations
介面主要使用應用程式域物件型別,使您可以使用應用程式資料。query
方法變體接受投影型別,模板使用 Spring Data Commons Projection 基礎設施將查詢結果應用於給定投影型別的例項。
此外,模板將分頁的 Lucene 查詢結果包裝在 Spring Data Commons Page
抽象的例項中。相同的投影邏輯仍然可以應用於頁面中的結果,並且在訪問集合中的每個頁面時會延遲投影。
例如,假設您有一個表示 Person
的類,如下所示
class Person {
Gender gender;
LocalDate birthDate;
String firstName;
String lastName;
...
String getName() {
return String.format("%1$s %2$s", getFirstName(), getLastName());
}
}
此外,您可能有一個單獨的介面來表示人員為 Customers
,具體取決於您的應用程式檢視,如下所示
interface Customer {
String getName()
}
如果我定義以下 LuceneIndex
…
@Bean
LuceneIndexFactoryBean personLastNameIndex(GemFireCache gemfireCache) {
LuceneIndexFactoryBean personLastNameIndex =
new LuceneIndexFactoryBean();
personLastNameIndex.setCache(gemfireCache);
personLastNameIndex.setFields("lastName");
personLastNameIndex.setRegionPath("/People");
return personLastNameIndex;
}
那麼您可以查詢人員作為 Person
物件,如下所示
List<Person> people = luceneTemplate.query("lastName: D*", "lastName", Person.class);
或者,您可以查詢型別為 Customer
的 Page
,如下所示
Page<Customer> customers = luceneTemplate.query("lastName: D*", "lastName", 100, 20, Customer.class);
然後可以使用 Page
獲取結果的各個頁面,如下所示
List<Customer> firstPage = customers.getContent();
方便的是,Spring Data Commons Page
介面還實現了 java.lang.Iterable<T>
,使其易於遍歷內容。
Spring Data Commons Projection 基礎設施的唯一限制是投影型別必須是介面。但是,可以擴充套件提供的 SDC Projection 基礎設施並提供自定義的 ProjectionFactory
,該工廠使用 CGLIB 生成代理類作為投影實體。
您可以使用 setProjectionFactory(:ProjectionFactory)
在 Lucene 模板上設定自定義 ProjectionFactory
。
12.2. 註解配置支援
最後,Spring Data for Apache Geode 為 LuceneIndexes
提供了註釋配置支援。
最終,SDG Lucene 支援將進入 Apache Geode 的 Repository 基礎設施擴充套件,以便 Lucene 查詢可以像 OQL 支援 今天的工作方式一樣,在應用程式 Repository
介面上的方法中表達。
但是,在此期間,如果您想方便地表達 LuceneIndexes
,您可以直接在應用程式域物件上執行此操作,如下面的示例所示
@PartitionRegion("People")
class Person {
Gender gender;
@Index
LocalDate birthDate;
String firstName;
@LuceneIndex;
String lastName;
...
}
要啟用此功能,您必須專門使用 SDG 的註釋配置支援,使用 @EnableEntityDefineRegions
和 @EnableIndexing
註釋,如下所示
@PeerCacheApplication
@EnableEntityDefinedRegions
@EnableIndexing
class ApplicationConfiguration {
...
}
LuceneIndexes 只能在 Apache Geode 伺服器上建立,因為 LuceneIndexes 僅適用於 PARTITION 區域。
|
根據我們之前對Person
類的定義,SDG 註解配置支援會找到Person
實體類定義,並確定人員儲存在名為“People”的PARTITION
區域中,並且Person
在birthDate
上有一個 OQL Index
,在lastName
上有一個LuceneIndex
。
13. 在 Apache Geode 中引導 Spring ApplicationContext
通常,基於 Spring 的應用程式透過使用 Spring Data for Apache Geode 的功能來引導 Apache Geode。透過指定使用 Spring Data for Apache Geode XML 名稱空間的<gfe:cache/>
元素,會在與您的應用程式相同的 JVM 程序中建立並初始化一個單一的嵌入式 Apache Geode 對等Cache
例項,並使用預設設定。
但是,有時可能需要(也許是您的 IT 組織的要求)由提供的 Apache Geode 工具套件完全管理和操作 Apache Geode,也許可以使用Gfsh。透過使用Gfsh,Apache Geode 會引導您的 Spring ApplicationContext
,而不是相反。Apache Geode 會代替應用程式伺服器或使用 Spring Boot 的 Java 主類來進行引導,並託管您的應用程式。
Apache Geode 不是應用程式伺服器。此外,在使用 Apache Geode 快取配置時,使用這種方法存在一些限制。 |
13.1. 使用 Apache Geode 引導使用 Gfsh 啟動的 Spring 上下文
為了在使用Gfsh啟動 Apache Geode 伺服器時在 Apache Geode 中引導 Spring ApplicationContext
,您必須使用 Apache Geode 的初始化器功能。初始化器塊可以宣告一個應用程式回撥,該回調在 Apache Geode 初始化快取後啟動。
初始化器是在initializer元素中使用 Apache Geode 的本機cache.xml
的最小程式碼片段來宣告的。為了引導 Spring ApplicationContext
,需要一個cache.xml
檔案,這與引導使用元件掃描配置的 Spring ApplicationContext
所需的 Spring XML 配置的最小程式碼片段(例如<context:component-scan base-packages="…"/>
)非常相似。
幸運的是,框架已經方便地提供了這樣的初始化器:SpringContextBootstrappingInitializer
.
以下示例顯示了 Apache Geode 的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>
然後,使用正確配置和構建的CLASSPATH
和cache.xml
檔案(如前所示)作為啟動 Apache Geode 伺服器時在 Gfsh 中指定的命令列選項,命令列將如下所示
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 名稱空間元素。這種方法的唯一限制是 Apache Geode 快取不能使用 SDG XML 名稱空間進行配置。換句話說,不能指定任何<gfe:cache/>
元素屬性(例如cache-xml-location
、properties-ref
、critical-heap-percentage
、pdx-serializer-ref
、lock-lease
等)。如果使用,這些屬性將被忽略。
這樣做的原因是 Apache Geode 本身已經在初始化程式被呼叫之前建立並初始化了快取。因此,快取已經存在,並且由於它是一個“單例”,因此無法重新初始化或增強其任何配置。
13.2. 延遲連線 Apache Geode 元件
Spring Data for Apache Geode 已經提供了對自動連線 Apache Geode 元件(例如CacheListeners
、CacheLoaders
、CacheWriters
等)的支援,這些元件由 Apache Geode 在cache.xml
中宣告和建立,使用 SDG 的WiringDeclarableSupport
類,如使用自動連線和註釋進行配置中所述。但是,這僅在 Spring 進行引導時有效(即,當 Spring 引導 Apache Geode 時)。
當您的 Spring ApplicationContext
由 Apache Geode 引導時,這些 Apache Geode 應用程式元件會被忽略,因為 Spring ApplicationContext
尚未存在。Spring ApplicationContext
直到 Apache Geode 呼叫初始化程式塊才會建立,而初始化程式塊僅在所有其他 Apache Geode 元件(快取、區域等)已經建立和初始化之後才會發生。
為了解決這個問題,引入了一個新的LazyWiringDeclarableSupport
類。這個新類知道 Spring ApplicationContext
。這個抽象基類的目的是,任何實現類都註冊自己,以便由 Spring 容器配置,該容器最終由 Apache Geode 在呼叫初始化程式後建立。從本質上講,這使您的 Apache Geode 應用程式元件有機會使用 Spring 容器中定義的 Spring bean 進行配置和自動連線。
為了使您的 Apache Geode 應用程式元件能夠由 Spring 容器自動連線,您應該建立一個擴充套件LazyWiringDeclarableSupport
的應用程式類,並註釋任何需要作為 Spring bean 依賴項提供的類成員,類似於以下示例
public class UserDataSourceCacheLoader extends LazyWiringDeclarableSupport
implements CacheLoader<String, User> {
@Autowired
private DataSource userDataSource;
...
}
如上面的CacheLoader
示例所示,您可能需要(儘管很少)在 Apache Geode cache.xml
中定義一個區域和一個CacheListener
元件。CacheLoader
可能需要訪問應用程式儲存庫(或者可能是 Spring ApplicationContext
中定義的 JDBC DataSource
)以在啟動時將Users
載入到 Apache Geode REPLICATE
區域中。
注意
以這種方式混合 Apache Geode 和 Spring 容器的不同生命週期時,請小心。並非所有用例和場景都受支援。Apache Geode 的 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.SpringContextBootstrappingInitializerIntegrationTests$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 Apache Geode 示例 儲存庫中。 |
Spring Data for Apache Geode 專案還包含一個示例應用程式。名為“Hello World”,該示例應用程式演示瞭如何在 Spring 應用程式中配置和使用 Apache Geode。在執行時,該示例提供了一個 shell,允許您對資料網格執行各種命令。它為不熟悉基本元件或 Spring 和 Apache Geode 概念的開發人員提供了一個極好的起點。
該示例與發行版捆綁在一起,並且基於 Maven。您可以將其匯入任何支援 Maven 的 IDE(例如 Spring Tool Suite)或從命令列執行它們。
14.1. Hello World
“Hello World”示例應用程式演示了 Spring Data for Apache Geode 專案的核心功能。它引導 Apache Geode,對其進行配置,對快取執行任意命令,並在應用程式退出時將其關閉。應用程式的多個例項可以同時啟動並協同工作,在沒有任何使用者干預的情況下共享資料。
在 Linux 下執行
如果您在啟動 Apache Geode 或示例時遇到網路問題,請嘗試將以下系統屬性 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 元件。
快取配置定義了 Apache Geode 快取、區域,以及為了說明目的而新增的 CacheListener
,它充當日誌記錄器。
主要 Bean 是 HelloWorld
和 CommandProcessor
,它們依賴於 GemfireTemplate
來與分散式結構互動。這兩個類都使用註解來定義它們的依賴項和生命週期回撥。
資源
附錄
附錄 A:名稱空間參考
<repositories />
元素
<repositories />
元素觸發 Spring Data 儲存庫基礎設施的設定。最重要的屬性是 base-package
,它定義了要掃描 Spring Data 儲存庫介面的包。參見“[repositories.create-instances.spring]”。下表描述了 <repositories />
元素的屬性。
名稱 | 描述 |
---|---|
|
定義要掃描的包,以查詢擴充套件 |
|
定義字尾以自動檢測自定義儲存庫實現。名稱以配置字尾結尾的類將被視為候選者。預設值為 |
|
確定用於建立查詢查詢的策略。有關詳細資訊,請參見“[repositories.query-methods.query-lookup-strategies]”。預設值為 |
|
定義要搜尋包含外部定義查詢的屬性檔案的位置。 |
|
是否應考慮巢狀的儲存庫介面定義。預設值為 |
附錄 B:填充程式名稱空間參考
<populator />
元素
<populator />
元素允許透過 Spring Data 儲存庫基礎設施填充資料儲存。[1]
名稱 | 描述 |
---|---|
|
從哪裡找到要讀取物件的儲存庫檔案,這些檔案將被填充。 |
附錄 C:儲存庫查詢關鍵字
支援的查詢方法主題關鍵字
下表列出了 Spring Data 儲存庫查詢推導機制通常支援的主題關鍵字,以表達謂詞。請參閱特定於儲存的文件以獲取支援的關鍵字的完整列表,因為此處列出的某些關鍵字可能在特定儲存中不受支援。
關鍵字 | 描述 |
---|---|
|
一般查詢方法,通常返回儲存庫型別、 |
|
存在投影,通常返回 |
|
返回數值結果的計數投影。 |
|
刪除查詢方法,返回無結果( |
|
將查詢結果限制為前 |
|
使用 distinct 查詢僅返回唯一結果。請查閱特定於儲存的文件,瞭解該功能是否受支援。此關鍵字可以出現在 |
支援的查詢方法謂詞關鍵字和修飾符
下表列出了 Spring Data 儲存庫查詢推導機制通常支援的謂詞關鍵字。但是,請查閱特定於儲存的文件以獲取支援的關鍵字的準確列表,因為此處列出的某些關鍵字可能在特定儲存中不受支援。
邏輯關鍵字 | 關鍵字表達式 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
除了過濾器謂詞之外,還支援以下修飾符列表
關鍵字 | 描述 |
---|---|
|
與謂詞關鍵字一起使用,用於不區分大小寫的比較。 |
|
忽略所有合適屬性的大小寫。在查詢方法謂詞中的某個地方使用。 |
|
指定一個靜態排序順序,後跟屬性路徑和方向(例如 |
附錄 D:儲存庫查詢返回型別
支援的查詢返回型別
下表列出了 Spring Data 儲存庫通常支援的返回型別。但是,請參閱特定於儲存的文件以獲取支援的返回型別的確切列表,因為此處列出的某些型別可能在特定儲存中不受支援。
地理空間型別(例如 GeoResult 、GeoResults 和 GeoPage )僅適用於支援地理空間查詢的資料儲存。某些儲存模組可能會定義自己的結果包裝器型別。
|
返回型別 | 描述 |
---|---|
|
表示沒有返回值。 |
基本型別 |
Java 基本型別。 |
包裝型別 |
Java 包裝型別。 |
|
一個唯一的實體。期望查詢方法最多返回一個結果。如果未找到結果,則返回 |
|
一個 |
|
一個 |
|
一個 |
|
一個 Java 8 或 Guava |
|
Scala 或 Vavr 的 |
|
Java 8 的 |
|
|
實現 |
公開建構函式或 |
Vavr |
Vavr 集合型別。有關詳細資訊,請參閱 [repositories.collections-and-iterables.vavr]。 |
|
一個 |
|
Java 8 的 |
|
一個 |
|
一個大小固定的資料塊,並指示是否有更多資料可用。需要 |
|
一個 |
|
一個結果條目,包含其他資訊,例如到參考位置的距離。 |
|
一個 |
|
一個 |
|
使用響應式儲存庫,一個 Project Reactor |
|
使用響應式儲存庫,一個 Project Reactor |
|
使用響應式儲存庫,一個 RxJava |
|
使用響應式儲存庫,一個 RxJava |
|
使用響應式儲存庫,一個 RxJava |