© 2010-2019 The original authors.

このドキュメントのコピーは、ご自身の使用および他者への配布のために作成することができます。ただし、かかるコピーに対して料金を請求しないこと、また、印刷物または電子形式で配布されるかどうかにかかわらず、各コピーにこの著作権通知が含まれていることが条件となります。

序文

Apache Geode 用の Spring Data は、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. 要件

Apache Geode の Spring Data には、Java 8.0、Spring Framework 5、Apache Geode (英語) 1.9.0 が必要です。

3. 新機能

1.2.0.RELEASE の時点で、以前は Spring GemFire として知られていたこのプロジェクトは、現在 Spring Data プロジェクトのモジュールであり、Apache Geode (英語) 上に構築されていることを反映して、Apache Geode では Spring Data に名前が変更されました。

3.1. 2.0 リリースの新機能

  • Apache Geode 9.1.1 にアップグレードしました。

  • Spring Data Commons 2.0.8.RELEASE にアップグレードしました。

  • Spring Framework 5.0.7.RELEASE にアップグレードしました。

  • さまざまなクラスとコンポーネントを関心事ごとにパッケージ化して、SDG コードベースを再編成しました。

  • 特に SD リポジトリ抽象化において、Java 8 型に対する広範なサポートが追加されました。

  • リポジトリインターフェースと抽象化が変更されました。たとえば、ID が java.io.Serializable である必要がなくなりました。

  • @EnableEntityDefinedRegions アノテーション ignoreIfExists 属性をデフォルトで true に設定します。

  • @Indexed アノテーション override 属性をデフォルトで false に設定します。

  • @EnableIndexes を @EnableIndexing に名前変更しました。

  • JavaConfig を使用するときにクライアントとサーバー間のキーと値の Interest を簡単かつ便利に表現するための InterestsBuilder クラスを導入しました。

  • オフヒープ、Redis アダプター、Apache Geode の新しいセキュリティフレームワークのアノテーション構成モデルのサポートが追加されました。

3.2. 2.1 リリースの新機能

  • Apache Geode 1.9.0 にアップグレードしました。

  • Spring Framework 5.1.0.RELEASE にアップグレードしました。

  • Spring Data Commons 2.1.0.RELEASE にアップグレードしました。

  • スナップショットの読み込み時にコールバックを呼び出すとともに、並列キャッシュ / リージョンスナップショットのサポートが追加されました。

  • リポジトリクエリメソッドから生成された OQL をカスタマイズするために QueryPostProcessors を登録するためのサポートが追加されました。

  • o.s.d.g.mapping.MappingPdxSerializer に TypeFilters を含める / 除外するサポートが追加されました。

  • ドキュメントを更新しました。

3.3. 2.2 リリースの新機能

  • Apache Geode 1.9.0 にアップグレードしました。

  • Spring Framework 5.2.0.RELEASE にアップグレードしました。

  • Spring Data Commons 2.2.0.RELEASE にアップグレードしました。

  • @LocatorApplication を使用して Apache Geode ロケーターアプリケーションを構成およびブートストラップするためのアノテーション構成サポートを追加します。

  • GatewayReceivers および GatewaySenders のアノテーション構成サポートが追加されました。

  • ドキュメントを更新しました。

リファレンスガイド

4. ドキュメント構造

次の章では、Spring Data が 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 Repositories では、基本的な CRUD と単純なクエリ操作を使用して、Spring Data リポジトリを作成し、使用して Apache Geode に保存されているデータにアクセスする方法について説明します。

  • 関数実行のアノテーションサポートでは、データが存在する場所で分散計算を実行するためにアノテーションを使用して Apache Geode 関数を作成し、使用する方法について説明します。

  • 継続的クエリ (CQ) では、Apache Geode の継続的クエリ (CQ) 機能を使用して、Apache Geode の OQL (オブジェクトクエリ言語) で定義および登録された関心に基づいてイベントストリームを処理する方法について説明します。

  • Apache Geode での Spring ApplicationContext のブートストラップでは、Gfsh を使用して Apache Geode サーバーで実行されている Spring ApplicationContext を構成およびブートストラップする方法について説明します。

  • サンプルアプリケーションでは、Apache Geode 用の Spring Data で利用できるさまざまな機能を説明するために、ディストリビューションに付属する例について説明します。

5. Spring コンテナーを使用した Apache Geode のブートストラップ

Apache Geode 用の Spring Data は、Spring IoC コンテナーを使用して、Apache Geode インメモリデータグリッド (IMDG) の完全な構成と初期化を提供します。フレームワークには、キャッシュ、リージョン、インデックス、DiskStores、関数、WAN ゲートウェイ、永続バックアップ、その他の分散システムコンポーネントなど、Apache Geode コンポーネントの構成を簡素化するクラスがいくつか含まれており、最小限の労力でさまざまなアプリケーションの使用例をサポートします。

このセクションでは、Apache Geode に関する基本的な知識があることを前提としています。詳細については、Apache Geode の製品ドキュメント [Apache] (英語) を参照してください。

5.1. Apache Geode cache.xml よりも Spring を使用する利点

Apache Geode の XML 名前空間用の Spring Data は、Apache Geode インメモリデータグリッド (IMDG) の完全な構成をサポートします。XML 名前空間は、Spring コンテナー内で Apache Geode のライフサイクルを適切に管理するために、Spring コンテキストで Apache Geode を構成する 2 つの方法のうちの 1 つです。Spring コンテキストで Apache Geode を構成するもう 1 つの方法は、アノテーションベースの構成を使用することです。

Apache Geode のネイティブ cache.xml のサポートはレガシーな理由から継続されますが、XML 構成を使用する Apache Geode アプリケーション開発者は、モジュール XML 構成、プロパティプレースホルダーとオーバーライド、SpEL (Spring 式言語 )、環境プロファイルなど、Spring が提供する多くの優れた機能を活用するために、すべてを Spring XML で実行することが推奨されます。XML 名前空間の背後では、Apache Geode の Spring Data は Spring の FactoryBean パターンを広範に使用して、Apache Geode コンポーネントの作成、構成、初期化を簡素化します。

Apache Geode は、開発者がカスタムイベントハンドラーを追加できる CacheListener、CacheLoader、CacheWriter などのコールバックインターフェースをいくつか提供します。Spring の IoC コンテナーを使用すると、これらのコールバックを通常の Spring Bean として構成し、Apache Geode コンポーネントに挿入できます。これは、比較的制限された構成オプションを提供し、コールバックで Apache Geode の Declarable インターフェースを実装する必要があるネイティブ cache.xml に比べて大幅に改善されています (Spring のコンテナー内で Declarables を引き続き使用できる方法については、Declarable コンポーネントの接続を参照してください)。

さらに、Eclipse Spring Tool Suite (STS) などの IDE は、コード補完、ポップアップアノテーション、リアルタイム検証などの Spring XML 名前空間の優れたサポートを提供します。

5.2. コア名前空間の使用

構成を簡素化するために、Apache Geode 用の Spring Data は、コア Apache Geode コンポーネントを構成するための専用の XML 名前空間を提供します。Spring の標準 <bean> 定義を使用して、Bean を直接構成することができます。ただし、すべての Bean プロパティは XML 名前空間を通じて公開されるため、生の Bean 定義を使用する利点はほとんどありません。

Spring における XML スキーマに基づく設定の詳細については、Spring Framework リファレンスドキュメントの付録を参照してください。
Spring Data リポジトリのサポートでは、別の XML 名前空間が使用されます。Apache Geode リポジトリ用に Spring Data を構成する方法の詳細については、Spring Data for Apache Geode Repositories を参照してください。

Apache Geode XML 名前空間に Spring Data を使用するには、次の例に示すように、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>
1Apache Geode XML 名前空間プレフィックスの場合は Spring Data。任意の名前で動作しますが、このリファレンスドキュメント全体では gfe が使用されます。
2XML 名前空間プレフィックスは URI にマップされます。
3XML 名前空間 URI の場所。場所が外部アドレス (存在し、有効) を指している場合でも、Spring は、Apache Geode ライブラリの Spring Data に含まれているため、スキーマをローカルで解決することに注意してください。
4gfe プレフィックスを持つ XML 名前空間を使用した宣言の例。

デフォルトの名前空間を beans から gfe に変更できます。これは、プレフィックスの宣言を回避するため、主に Apache Geode コンポーネントで構成された XML 構成に役立ちます。これを行うには、次の例に示すように、前に示した名前空間プレフィックス宣言を入れ替えます。

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

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

  <cache ...> (4)

</beans>
1 この XML ドキュメントのデフォルトの名前空間宣言は、Apache Geode XML 名前空間の Spring Data を指します。
2Spring の生の Bean 定義の beans 名前空間プレフィックス宣言。
3beans 名前空間を使用した Bean 宣言。プレフィックスに注意してください。
4gfe 名前空間を使用した Bean 宣言。gfe がデフォルトの名前空間であるため、プレフィックスがないことに注意してください。

5.3. データアクセス名前空間の使用

Spring Data for Apache Geode は、コア XML 名前空間(gfe)に加えて、主に Apache Geode クライアントアプリケーションの開発を簡素化することを目的としたデータアクセス XML 名前空間(gfe-data)を提供します。この名前空間には現在、Apache Geode リポジトリと関数実行のサポート、および Apache Geode クラスタへの接続を容易にする <datasource> タグが含まれています。

5.3.1. Apache Geode に簡単に接続する方法

多くのアプリケーションでは、デフォルト値を使用した Apache Geode データグリッドへの基本的な接続で十分です。Apache Geode の <datasource> タグに対応する Spring Data は、データへのアクセスを容易にします。データソースは ClientCache と接続 Pool を作成します。さらに、クラスターサーバーに対して既存のすべてのルートリージョンを照会し、それぞれに対して(空の)クライアントリージョンプロキシを作成します。

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

<datasource> タグは構文的に <gfe:pool> に似ています。既存のデータグリッドに接続するために、1 つ以上のネストされた locator または server 要素を設定できます。さらに、プールの設定に使用できるすべての属性がサポートされています。この設定により、ロケータに接続されたクラスタメンバーに定義された各リージョンに対してクライアントリージョン 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 ごとに)オープンできるキャッシュは 1 つだけです。ほとんどの場合、キャッシュは 1 回だけ作成する必要があります。

このセクションでは、ピアツーピア(P2P)トポロジおよびキャッシュサーバーに適したピア Cache メンバーの作成と構成について説明します。Cache メンバーは、スタンドアロンアプリケーションや統合テストでも使用できます。ただし、一般的な本番システムでは、ほとんどのアプリケーションプロセスがキャッシュクライアントとして動作し、代わりに ClientCache インスタンスを作成します。これについては、Apache Geode ClientCache の設定およびクライアント領域のセクションで説明します。

デフォルト構成のピア Cache は、次の簡単な宣言で作成できます。

<gfe:cache/>

Spring コンテナーの初期化中に、このキャッシュ定義を含む ApplicationContext は、CacheFactoryBean を登録します。CacheFactoryBean は、Apache Geode Cache インスタンスを参照する gemfireCache という名前の Spring Bean を作成します。この Bean は、既存の Cache を参照するか、まだ存在しない場合は新しく作成された Cache を参照します。追加のプロパティが指定されていないため、新しく作成された Cache はデフォルトのキャッシュ構成を適用します。

Cache に依存する Spring Data for Apache Geode コンポーネントはすべてこの命名規則に従うため、Cache への依存関係を明示的に宣言する必要はありません。必要に応じて、SDG XML の様々な名前空間要素が提供する cache-ref 属性を使用して、依存関係を明示的に宣言することもできます。また、次のように id 属性を使用して、キャッシュの Bean 名をオーバーライドすることもできます。

<gfe:cache id="myCache"/>

Apache Geode Cache は Spring を使用して完全に設定できます。ただし、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 設定ファイルを参照するだけでなく、Spring の Properties サポート機能を利用する Apache Geode システムプロパティ [Apache] (英語) を指定することもできます。

たとえば、次のように、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>

アプリケーション構成の外部で環境固有の設定を外部化する場合は、プロパティファイルを使用することをお勧めします。

キャッシュ設定は、新しいキャッシュを作成する必要がある場合にのみ適用されます。VM 内にすでに開いているキャッシュが存在する場合、これらの設定は無視されます。

5.4.1. 高度なキャッシュ構成

高度なキャッシュ構成の場合、cache 要素は、次のように、属性または子要素として公開されるいくつかの構成オプションを提供します。

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

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

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

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

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

</gfe:cache>
1 属性はさまざまなキャッシュオプションをサポートしています。この例に示されている内容の詳細については、Apache Geode の製品ドキュメント (英語) を参照してください。close 属性は、Spring アプリケーションコンテキストが閉じられたときにキャッシュを閉じるかどうかを決定します。デフォルトは true です。ただし、複数のアプリケーションコンテキストがキャッシュを使用するユースケース (Web アプリケーションでよく見られる) では、この値を false に設定してください。
2enable-auto-reconnect 属性を true (デフォルトは false)に設定すると、切断された Apache Geode メンバーが自動的に再接続し、Apache Geode クラスタに再参加します。詳細については、Apache Geode 製品ドキュメント [Apache] (英語) を参照してください。
3use-bean-factory-locator 属性を true に設定すると(デフォルトは false)、Spring(XML)構成メタデータと Apache Geode cache.xml の両方が Apache Geode キャッシュノード(クライアントまたはピア)の構成に使用されている場合にのみ適用されます。このオプションにより、cache.xml で表現された Apache Geode コンポーネント(CacheLoader など)が、Spring アプリケーションコンテキストで定義された Bean(DataSource など)と自動的に関連付けられます。このオプションは通常、cache-xml-location と組み合わせて使用されます。
4use-cluster-configuration 属性を true に設定すると(デフォルトは false)、Apache Geode メンバーはロケーターから共通の共有クラスタベース構成を取得できるようになります。詳細については、Apache Geode 製品ドキュメント [Apache] (英語) を参照してください。
5Bean 参照を使用する TransactionListener コールバック宣言の例。参照先の Bean は TransactionListener [Apache] (英語) を実装する必要があります。TransactionListener は、トランザクション関連イベント(afterCommit や afterRollback など)を処理するために実装できます。
6 内部の Bean 宣言を使用した TransactionWriter コールバック宣言の例。Bean は TransactionWriter [Apache] (英語) を実装する必要があります。TransactionWriter はトランザクションを拒否できるコールバックです。
7Bean 参照を使用した GatewayConflictResolver コールバック宣言の例。参照先の Bean は https://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/util/GatewayConflictResolver.html (英語) [GatewayConflictResolver] を実装する必要があります。GatewayConflictResolver は、他のシステムで発生し、WAN ゲートウェイを介して到着したイベントの処理方法を決定するために呼び出される Cache -level プラグインです。分散型リージョン作成サービスを提供します。
8Apache Geode トランザクションに外部 DataSource を参加させるための JNDI バインディングを宣言します。
PDX 直列化を有効にする

上記の例には、Apache Geode の拡張直列化フレームワークである PDX に関連する属性がいくつか含まれています。PDX の詳細な説明はこのリファレンスガイドの範囲外ですが、PDX は PdxSerializer を登録することで有効化され、pdx-serializer 属性を設定することで有効化されることに注意してください。

Apache Geode は、Java リフレクションを使用する実装クラス(org.apache.geode.pdx.ReflectionBasedAutoSerializer)を提供します。ただし、開発者が独自の実装を提供することは一般的です。属性の値は、PdxSerializer インターフェースを実装する Spring Bean への参照です。

直列化サポートの詳細については、Apache Geode 直列化の操作を参照してください。

自動再接続を有効にする

<gfe:cache enable-auto-reconnect="[true|false*]> 属性を true に設定する場合は注意が必要です。

一般的に、「自動再接続」は、Apache Geode 用の Spring Data の XML 名前空間を使用して、クラスタに追加された新しい非アプリケーション Apache Geode サーバーの設定とブートストラップを行う場合にのみ有効にする必要があります。言い換えれば、Apache Geode 用の Spring Data を使用して、Apache Geode クラスタのピア Cache メンバーでもある Apache Geode アプリケーションを開発・構築する場合は、「自動再接続」を有効にしないでください。

この制限の主な理由は、ほとんどの Apache Geode アプリケーションがデータアクセス操作を実行するために Apache Geode の Cache またはリージョンへの参照を使用していることです。これらの参照は、Spring コンテナーによってアプリケーションコンポーネント(リポジトリなど)に「挿入」され、アプリケーションで使用されます。ピアメンバーがクラスタの他の部分から強制的に切断された場合(ピアメンバーが応答しなくなった場合や、ネットワークパーティションによって 1 つ以上のピアメンバーが独立した分散システムとして機能するには小さすぎるグループに分割された場合など)、ピアメンバーはシャットダウンし、すべての Apache Geode コンポーネント参照(キャッシュ、リージョンなど)が無効になります。

本質的には、各ピアメンバーの現在の強制切断処理ロジックは、システムを根本から破壊します。JGroups スタックはシャットダウンし、分散システムはシャットダウン状態になり、最終的にキャッシュが閉じられます。実質的に、すべてのメモリ参照は古くなり、失われます。

分散システムから切断された後、ピアメンバーは「再接続中」状態に入り、定期的に分散システムへの再参加を試みます。ピアメンバーが再接続に成功すると、既存のメンバーから分散システムの「ビュー」を再構築し、新しい分散システム ID を受け取ります。さらに、すべてのキャッシュ、リージョン、その他の Apache Geode コンポーネントも再構築されます。Spring コンテナーによってアプリケーションに挿入された可能性のある古い参照はすべて古くなり、無効になります。

Apache Geode は、(Apache Geode のパブリック Java API を使用している場合でも)アプリケーションキャッシュ、リージョン、その他のコンポーネント参照が再接続操作によって自動的にリフレッシュされることを保証しません。そのため、Apache Geode アプリケーションは、自身の参照を注意深くリフレッシュする必要があります。

残念ながら、切断イベントとそれに続く再接続イベントを通知する方法はありません。もしそうであれば、アプリケーションが ConfigurableApplicationContext.refresh() を呼び出す必要があるかどうかを明確に判断できるはずです(ただし、ConfigurableApplicationContext.refresh() を呼び出すことがアプリケーションに可能であればの話ですが)。そのため、Apache Geode のこの「機能」は、ピア Cache アプリケーションには推奨されません。

「自動再接続」の詳細については、Apache Geode の製品ドキュメント [Apache] (英語) を参照してください。

クラスタベースの構成の使用

Apache Geode のクラスタ構成サービスは、クラスタに参加するすべてのピアメンバーが、ロケータによって維持される共有の永続的な構成を使用して、クラスタの「一貫性のあるビュー」を取得できる便利な方法です。クラスタベースの構成を使用することで、ピアメンバーが参加した際に、その構成が Apache Geode 分散システムと互換性があることが保証されます。

Apache Geode 用の Spring Data のこの機能 (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"/>
Gfsh などの一部の Apache Geode ツールでは、スキーマのような変更(例: gfsh>create region --name=Example --type=PARTITION)が行われるとアクションが「記録」されますが、Apache Geode の設定メタデータの Spring Data は記録されません。Apache Geode の公開 Java API を直接使用した場合も同様です。これも記録されません。

Apache Geode のクラスタ構成サービスに関する詳細については、製品ドキュメント [Apache] (英語) を参照してください。

5.4.2. Apache Geode CacheServer の設定

Apache Geode 用の Spring Data には、CacheServer [Apache] (英語) を構成するための専用サポートが含まれており、次の例に示すように、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 のコンテキスト (英語) 名前空間を使用して property-placeholder を宣言します。プロパティプレースホルダー (英語) は 1 つ以上のプロパティファイルを読み込み、実行時にプロパティプレースホルダーを値に置き換えます。これにより、管理者はメインアプリケーション構成に手を加えることなく値を変更できます。Spring はまた、SpEL (英語) と環境抽象化 (英語) を提供し、環境固有のプロパティをメインコードベースから外部化することで、複数のマシン間での デプロイを容易にします。
初期化の問題を回避するため、Spring Data によって Apache Geode 用に起動される CacheServer は、Spring コンテナーが完全に初期化された後に起動されます。これにより、宣言的に定義される潜在的なリージョン、リスナー、ライター、インスタンシエータは、サーバーが接続の受け入れを開始する前に完全に初期化および登録されます。これらの要素をプログラムで設定する際には、この点に留意してください。サーバーがコンポーネントよりも先に起動し、すぐに接続してくるクライアントから認識されない場合があるためです。

5.4.3. Apache Geode ClientCache の設定

Apache Geode の Spring Data は、Apache Geode ピア Cache [Apache] (英語) の定義に加えて、Spring コンテナー内の Apache Geode ClientCache [Apache] (英語) の定義もサポートします。ClientCache の定義は、設定と使用方法が Apache Geode ピアキャッシュに似ており、org.springframework.data.gemfire.client.ClientCacheFactoryBean でサポートされます。

デフォルト設定を使用した Apache Geode キャッシュクライアントの最も単純な定義は次のとおりです。

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

client-cache は、キャッシュ要素と同じオプションを多くサポートしています。ただし、完全なピア Cache メンバーとは異なり、キャッシュクライアントはプールを介してリモートキャッシュサーバーに接続します。デフォルトでは、localhost 上で実行され、ポート 40404 をリッスンしているサーバーに接続するためのプールが作成されます。リージョンが特定のプールを使用するように設定されていない限り、デフォルトのプールはすべてのクライアントリージョンで使用されます。

プールは pool 要素で定義できます。このクライアント側プールは、個々のエンティティ、または 1 つ以上のロケータを介してキャッシュ全体に対して、サーバーへの直接接続を設定するために使用できます。

たとえば、client-cache で使用されるデフォルトのプールをカスタマイズするには、開発者はプールを定義し、それをキャッシュ定義に接続する必要があります。次の例を参照してください。

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

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

<client-cache> 要素には ready-for-events 属性もあります。この属性が true に設定されている場合、クライアントキャッシュの初期化には ClientCache.readyForEvents() [Apache] (英語) の呼び出しが含まれます。

クライアント領域では、クライアント側の構成についてさらに詳しく説明します。

Apache Geode の DEFAULT プールと Apache Geode の Spring Data プールの定義

Apache Geode ClientCache がローカル専用の場合、プール定義は不要です。たとえば、以下のように定義できます。

<gfe:client-cache/>

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

この場合、「例」のリージョンは LOCAL であり、クライアントとサーバー間でデータは分散されません。プールは必要ありません。これは、Apache Geode の ClientRegionShortcut [Apache] (英語) (すべての LOCAL_* ショートカット)で定義される、クライアント側のローカルのみのリージョンすべてに当てはまります。

ただし、クライアントの Region がサーバー側の Region への(キャッシュ)プロキシである場合は、Pool が必要です。その場合、Pool を定義して使用する方法はいくつかあります。

ClientCache、プール、プロキシベースのリージョンがすべて定義されているが、明示的に識別されていない場合、次の例に示すように、Apache Geode の Spring Data によって参照が自動的に解決されます。

<gfe:client-cache/>

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

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

上の例では、ClientCache は gemfireCache、プールは gemfirePool、クライアントリージョンは "Example" として識別されています。ただし、ClientCache は Apache Geode の DEFAULT プールを gemfirePool から初期化し、クライアントリージョンはクライアントとサーバー間でデータを分散する際に gemfirePool を使用します。

基本的に、Apache Geode 用の Spring Data は、前述の構成を次のように解決します。

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

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

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

Apache Geode は依然として DEFAULT というプールを作成します。Apache Geode の Spring Data は、DEFAULT プールを gemfirePool から初期化します。これは、複数のプールが定義されており、クライアント領域が別々のプールを使用している場合、またはプールを全く宣言していない場合に便利です。

次のことを考慮してください。

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

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

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

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

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

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

この設定では、Apache Geode client-cache DEFAULT プールは、pool-name 属性で指定されているように、locatorPool から初期化されます。両方のプールが明示的に識別(命名)されているため、Apache Geode 定義の gemfirePool には Spring Data は存在しません(それぞれ locatorPool と serverPool)。

"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. リージョンの設定

キャッシュへのデータの保存と取得には、Region が必要です。org.apache.geode.cache.Region は java.util.Map を継承したインターフェースで、使い慣れたキーバリューセマンティクスを用いた基本的なデータアクセスを可能にします。Region インターフェースは、それを必要とするアプリケーションクラスに組み込まれるため、Region 型自体はプログラミングモデルから分離されます。通常、各 Region は、リレーショナルデータベースのテーブルと同様に、1 つのドメインオブジェクトに関連付けられます。

Apache Geode は次の型のリージョンを実装します。

  • REPLICATE - データは、リージョンを定義するクラスター内のすべてのキャッシュメンバーに複製されます。これにより、非常に高い読み取りパフォーマンスが得られますが、書き込みはレプリケーションの実行に時間がかかります。

  • PARTITION - データは、リージョンを定義するクラスター内の多数のキャッシュメンバー間でバケットに分割(シャーディング)されます。これにより、高い読み取りおよび書き込みパフォーマンスが得られ、単一ノードでは大きすぎる大規模なデータセットにも適しています。

  • LOCAL - データはローカルノードにのみ存在します。

  • クライアント - 技術的には、クライアントリージョンは、クラスタ内のキャッシュサーバーでホストされているレプリケートリージョンまたはパーティションリージョンのプロキシとして機能するローカルリージョンです。ローカルで作成または取得されたデータを保持できます。また、空のままにすることもできます。ローカルでの更新はキャッシュサーバーに同期されます。また、クライアントリージョンは、同じサーバーリージョンにアクセスするリモートプロセスからの変更を常に最新の状態(同期)に保つために、イベントをサブスクライブできます。

さまざまなリージョン型とその機能および構成オプションの詳細については、Apache Geode の領域型 [Apache] (英語) に関するドキュメントを参照してください。

5.5.1. 外部で構成されたリージョンの使用

Apache Geode ネイティブ cache.xml ファイルですでに設定されているリージョンを参照するには、lookup-region 要素を使用します。name 属性で対象のリージョン名を宣言するだけです。例: 既存の Orders というリージョンに対して、ordersRegion として識別される Bean 定義を宣言するには、次の Bean 定義を使用します。

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

name が指定されていない場合、Bean の id がリージョン名として使用されます。上記の例は次のようになります。

<!-- lookup for a Region called 'Orders' -->
<gfe:lookup-region id="Orders"/>
リージョンが存在しない場合は、初期化例外がスローされます。新しいリージョンを設定するには、以下の該当するセクションに進んでください。

前の例では、キャッシュ名が明示的に定義されていなかったため、デフォルトの命名規則(gemfireCache)が使用されました。代わりに、cache-ref 属性を使用してキャッシュ Bean を参照することもできます。

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

lookup-region を使用すると、リージョンのセマンティクスやセットアップインフラストラクチャを公開せずに、既存の事前構成済みのリージョンを取得できます。

5.5.2. 自動領域検索

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"/>) を使用して、特定の Region を Spring コンテナー内の Bean として参照するか、次のようにして cache.xml で定義されているすべての Region をインポートすることもできます。

<gfe:auto-region-lookup/>

Apache Geode の Spring Data は、明示的な <gfe:lookup-region> Bean 宣言によって Spring コンテナーに明示的に追加されていない、cache.xml で定義されているすべての Apache Geode 領域に対して Bean を自動的に作成します。

Apache Geode の Spring Data は、キャッシュが作成および初期化された後に Spring BeanPostProcessor (Javadoc) を使用してキャッシュを後処理し、Apache Geode で定義された領域を決定して、Spring ApplicationContext に Bean として追加することを認識することが重要です。

これらの「自動検索」された領域は、Spring ApplicationContext で定義されている他の Bean と同様に挿入できますが、1 つの例外があります。次のように、‘ gemfireCache ’ Bean との depends-on 関連付けを定義する必要があります。

package example;

import ...

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

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

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

    ...
}

上記の例は、Spring の component-scan 機能を使用する場合にのみ適用されます。

Spring XML 構成を使用してコンポーネントを宣言する場合は、次のようにします。

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

こうすることで、<gfe:auto-region-lookup> 要素を使用するときに、オートワイヤー参照を持つコンポーネントの前に、Apache Geode キャッシュと cache.xml で定義されたすべての領域が作成されるようになります。

5.5.3. 領域の構成

Apache Geode 用の Spring Data は、次の要素を通じてあらゆる型のリージョンを構成するための包括的なサポートを提供します。

  • ローカル領域: <local-region>

  • パーティション領域: <partitioned-region>

  • 複製領域: <replicated-region>

  • クライアント領域: <client-region>

領域型 [Apache] (英語) の包括的な説明については、Apache Geode のドキュメントを参照してください。

共通リージョン属性

次の表は、すべてのリージョン型で使用できる属性を示しています。

表 1: 共通リージョン属性
名前 値 説明

cache-ref

Apache Geode キャッシュ Bean 参照

Apache Geode キャッシュを定義する Bean の名前 (デフォルトでは "gemfireCache" )。

cloning-enabled

boolean (default: false)

true の場合、更新は値のクローンに適用され、クローンがキャッシュに保存されます。false の場合、値はキャッシュ内でその場で変更されます。

close

boolean (default: false)

シャットダウン時に領域を閉じるかどうかを決定します。

concurrency-checks-enabled

boolean (default: true)

分散領域への同時更新または順序外更新に対して一貫した処理を提供するために、メンバーがチェックを実行するかどうかを決定します。

data-policy

Apache Geode のデータポリシー [Apache] (英語) を参照してください。

リージョンのデータポリシー。すべてのデータポリシーがすべてのリージョン型でサポートされているわけではないことに注意してください。

destroy

boolean (default: false)

シャットダウン時に領域を破棄するかどうかを決定します。

disk-store-ref

構成されたディスクストアの名前。

disk-store 要素を通じて作成された Bean への参照。

disk-synchronous

boolean (default: true)

ディスクストアの書き込みが同期的かどうかを決定します。

id

任意の有効な Bean 名。

name 属性が指定されていない場合のデフォルトの領域名。

ignore-if-exists

boolean (default: false)

領域がすでにキャッシュ内に存在する場合はこの Bean 定義を無視し、代わりに検索を実行します。

ignore-jta

boolean (default: false)

このリージョンが JTA (Java Transaction API) トランザクションに参加するかどうかを決定します。

index-update-type

synchronous or asynchronous (default: synchronous)

Determines whether Indices are updated synchronously or asynchronously on entry creation.

initial-capacity

integer (default: 16)

The initial memory allocation for the number of Region entries.

key-constraint

Any valid, fully-qualified Java class name.

Expected key type.

load-factor

float (default: .75)

Sets the initial parameters on the underlying java.util.ConcurrentHashMap used for storing region entries.

name

Any valid region name.

The name of the region. If not specified, it assumes the value of the id attribute (that is, the bean name).

persistent

*boolean (default: false)

Determines whether the region persists entries to local disk (disk store).

shortcut

See https://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/RegionShortcut.html (英語)

The RegionShortcut for this region. Allows easy initialization of the region based on pre-defined defaults.

statistics

boolean (default: false)

Determines whether the region reports statistics.

template

The name of a region template.

A reference to a bean created through one of the *region-template elements.

value-constraint

Any valid, fully-qualified Java class name.

Expected value type.

CacheListener instances

CacheListener instances are registered with a Region to handle Region events, such as when entries are created, updated, destroyed, and so on. A CacheListener can be any bean that implements the CacheListener [Apache] (英語) interface. A Region may have multiple listeners, declared with the cache-listener element nested in the containing *-region element.

The following example has two declared CacheListener’s. The first references a named, top-level Spring bean. The second is an anonymous inner bean definition.

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

The following example uses an alternate form of the cache-listener element with the ref attribute. Doing so allows for more concise configuration when defining a single CacheListener.

Note: The XML namespace allows only a single cache-listener element, so either the style shown in the preceding example or the style in the following example must be used.

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

  <bean id="myListener" class="example.CacheListener"/>
</beans>
Using ref and a nested declaration in the cache-listener element is illegal. The two options are mutually exclusive and using both in the same element results in an exception.
Bean Reference Conventions

The cache-listener element is an example of a common pattern used in the XML namespace anywhere Apache Geode provides a callback interface to be implemented in order to invoke custom code in response to cache or Region events. When you use Spring’s IoC container, the implementation is a standard Spring bean. In order to simplify the configuration, the schema allows a single occurrence of the cache-listener element, but, if multiple instances are permitted, it may contain nested bean references and inner bean definitions in any combination. The convention is to use the singular form (that is, cache-listener vs cache-listeners), reflecting that the most common scenario is, in fact, a single instance. We have already seen examples of this pattern in the advanced cache configuration example.

CacheLoaders and CacheWriters

Similar to cache-listener, the XML namespace provides cache-loader and cache-writer elements to register these Apache Geode components for a Region.

A CacheLoader is invoked on a cache miss to let an entry be loaded from an external data source, such as a database. A CacheWriter is invoked before an entry is created or updated, to allow the entry to be synchronized to an external data source. The main difference is that Apache Geode supports, at most, a single instance of CacheLoader and CacheWriter per Region. However, either declaration style may be used.

The following example declares a Region with both a CacheLoader and a 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>

See CacheLoader [Apache] (英語) and CacheWriter [Apache] (英語) in the Apache Geode documentation for more details.

5.5.4. Compression

Apache Geode Regions may also be compressed in order to reduce JVM memory consumption and pressure to possibly avoid global GCs. When you enable compression for a Region, all values stored in memory for the Region are compressed, while keys and indexes remain uncompressed. New values are compressed when put into the Region and all values are decompressed automatically when read back from the Region. Values are not compressed when persisted to disk or when sent over the wire to other peer members or clients.

The following example shows a Region with compression enabled:

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

See Apache Geode’s documentation for more information on Region Compression [Apache] (英語) .

5.5.5. Off-Heap

Apache Geode Regions may also be configured to store Region values in off-heap memory, which is a portion of JVM memory that is not subject to Garbage Collection (GC). By avoid expensive GC cycles, your application can spend more of its time on things that matter, like processing requests.

Using off-heap memory is as simple as declaring the amount of memory to use and then enabling your Regions to use off-heap memory, as shown in the following configuration:

<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"/>

You can control other aspects of off-heap memory management by setting the following Apache Geode configuration properties using the <gfe:cache> element:s

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

Apache Geode’s ResourceManager will use these two threshold values (critical-off-heap-percentage & eviction-off-heap-percentage) to more effectively manage the off-heap memory in much the same way as the JVM does when managing heap memory. Apache Geode ResourceManager will prevent the cache from consuming too much off-heap memory by evicting old data. If the off-heap manager is unable to keep up, then the ResourceManager refuses additions to the cache until the off-heap memory manager has freed up an adequate amount of memory.

See Apache Geode’s documentation for more information on Managing Heap and Off-Heap Memory [Apache] (英語) .

Specifically, read the section, Managing Off-Heap Memory [Apache] (英語) .

5.5.6. Subregions

Spring Data for Apache Geode also supports Sub-Regions, allowing Regions to be arranged in a hierarchical relationship.

For example, Apache Geode allows for a /Customer/Address Region and a different /Employee/Address Region. Additionally, a Sub-Region may have its own Sub-Regions and configuration. A Sub-Region does not inherit attributes from its parent Region. Regions types may be mixed and matched subject to Apache Geode constraints. A Sub-Region is naturally declared as a child element of a Region. The Sub-Region’s name attribute is the simple name. The preceding example might be configured as follows:

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

Note that the Monospaced ([id]) attribute is not permitted for a Sub-Region. Sub-Regions are created with bean names (/Customer/Address and /Employee/Address, respectively, in this case). So they may be injected into other application beans, such as a GemfireTemplate, that need them by using the full path name of the Region. The full pathname of the Region should also be used in OQL query strings.

5.5.7. Region Templates

Spring Data for Apache Geode also supports Region templates.

This feature allows developers to define common Region configuration and attributes once and reuse the configuration among many Region bean definitions declared in the Spring ApplicationContext.

Spring Data for Apache Geode includes five Region template tags in its namespace:

Table 2. Region Template Tags
Tag Name Description

<gfe:region-template>

共通の汎用リージョン属性を定義します。XML 名前空間で regionType を拡張します。

<gfe:local-region-template>

共通の「ローカル」リージョン属性を定義します。XML 名前空間で localRegionType を拡張します。

<gfe:partitioned-region-template>

共通の "PARTITION" リージョン属性を定義します。XML 名前空間で partitionedRegionType を拡張します。

<gfe:replicated-region-template>

共通の "REPLICATE" リージョン属性を定義します。XML 名前空間で replicatedRegionType を拡張します。

<gfe:client-region-template>

共通の「クライアント」リージョン属性を定義します。XML 名前空間で clientRegionType を拡張します。

タグに加えて、具体的な <gfe:*-region> 要素(および抽象 <gfe:*-region-template> 要素)には、リージョンの設定を継承するリージョンテンプレートを定義する template 属性があります。リージョンテンプレートは、他のリージョンテンプレートから継承することもできます。

次の例は、可能な構成の 1 つを示しています。

<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" を継承し、"PartitionRegionTemplate" は "ExtendedRegionTemplate" を継承し、"BaseRegionTemplate" は "BaseRegionTemplate" を継承していることに注意してください。後続の継承されたリージョン Bean 定義で定義された属性とサブ要素は、親の定義をオーバーライドします。

テンプレートの仕組み

Apache Geode 用の Spring Data は、Spring の ApplicationContext 構成メタデータを解析する際にリージョンテンプレートを適用するため、リージョンテンプレートは継承順に宣言する必要があります。つまり、親テンプレートは子テンプレートよりも先に定義する必要があります。これにより、特に要素属性やサブ要素がオーバーライドされる場合でも、適切な構成が適用されます。

同様に重要なのは、Region 型は他の同様の型の Region からのみ継承できるということです。たとえば、<gfe:replicated-region> は <gfe:partitioned-region-template> から継承することはできません。
リージョンテンプレートは単一継承です。
領域、サブ領域、検索に関する注意事項

以前は、Spring Data for Apache Geode XML 名前空間の replicated-region、partitioned-region、local-region、client-region 要素の基盤となるプロパティの一つは、Region の作成を試みる前にまずルックアップを実行するというものでした。これは、Region がすでに存在する場合、つまりインポートされた Apache Geode ネイティブ cache.xml 構成ファイルで Region が定義されている場合に、その状況が発生する可能性があるためです。そのため、エラーを回避するために、まずルックアップが実行されていました。これは仕様であり、変更される可能性があります。

この動作は変更され、デフォルトの動作ではまずリージョンを作成するようになりました。リージョンがすでに存在する場合、作成ロジックは失敗し、適切な例外がスローされます。ただし、CREATE TABLE IF NOT EXISTS …​ DDL 構文と同様に、Apache Geode <gfe:*-region> XML 名前空間要素の Spring Data に 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 として Bean として参照されます。lookup-region 要素と対応する構文(前述)を使用する利点は、親リージョン(この場合は Customers)に不必要に Bean を定義することなく、サブリージョンを直接参照できることです。

ネストされた形式を使用するように構成メタデータ構文を変更する次の悪い例を検討してください。

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

ここで、トップレベルの replicated-region 要素と ignore-if-exists 属性セットを使用して最初に検索を実行する別の悪い例を考えてみましょう。

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

Spring ApplicationContext で定義されている Region Bean は、以下の要素で構成されています: { "Customers", "/Customers/Accounts", "/Customers/Accounts/Orders" }. これは、前の例で示した依存性注入参照 (つまり @Resource(name = "Customers/Accounts")) が壊れていることを意味します。これは、Customers/Accounts という名前の Bean が実際には定義されていないためです。そのため、前の 2 つの例のように Region を設定しないでください。

Apache Geode は、親リージョンとサブリージョンの両方を、先頭のスラッシュの有無にかかわらず柔軟に参照できます。例: 親リージョンは /Customers または Customers として参照し、子リージョンは /Customers/Accounts または Customers/Accounts として参照できます。ただし、Apache Geode の Spring Data は、リージョンにちなんで Bean に名前を付ける際に非常に限定的です。サブリージョンを表すために常にスラッシュ(/)を使用します(例: /Customers/Accounts)。

前述のネストされていない lookup-region 構文を使用するか、次のように先頭にスラッシュ (/) を付けて直接参照を定義する必要があります。

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

前述の例では、サブリージョンを参照するためにネストされた replicated-region 要素が使用されており、前述の問題が示されています。顧客、アカウント、オーダーの各リージョンとサブリージョンは永続的でしょうか? これらのリージョンはネイティブの Apache Geode cache.xml 構成ファイルで REPLICATE として定義されており、キャッシュ Bean が初期化される前(<gfe:cache> 要素が処理された後)に存在するため、永続的ではありません。

5.5.8. データの削除 (オーバーフローあり)

様々な制約に基づき、各リージョンはメモリからデータを追い出すためのエビクションポリシーを設定できます。現在、Apache Geode では、エビクションは最長時間未使用エントリ(LRU [Wikipedia] (英語) とも呼ばれます)に適用されます。追い出されたエントリは破棄されるか、ディスクにページングされます(「ディスクオーバーフロー」と呼ばれます)。

Apache Geode の Spring Data は、ネストされた eviction 要素を使用して、PARTITION リージョン、REPLICATE リージョン、クライアント、ローカルリージョンのすべての削除ポリシー (エントリ数、メモリ、ヒープ使用量) をサポートします。

たとえば、メモリサイズが 512 MB を超えた場合に PARTITION 領域をディスクにオーバーフローするように構成するには、次の構成を指定します。

<gfe:partitioned-region id="examplePartitionRegionWithEviction">
  <gfe:eviction type="MEMORY_SIZE" threshold="512" action="OVERFLOW_TO_DISK"/>
</gfe:partitioned-region>
レプリカは local destroy エビクションを使用できません。local destroy エビクションを使用するとレプリカが無効化されるためです。詳細については、Apache Geode のドキュメントを参照してください。

オーバーフロー用にリージョンを構成する場合は、効率を最大限に高めるために、disk-store 要素を通じてストレージを構成する必要があります。

削除ポリシーの詳細な説明については、追い出し [Apache] (英語) の Apache Geode ドキュメントを参照してください。

5.5.9. データの有効期限

Apache Geode を使用すると、キャッシュ内のエントリの存続期間を制御できます。エントリの有効期限は経過時間によって決まりますが、エントリの削除はエントリ数、ヒープ、メモリ使用量によって決まります。エントリの有効期限が切れると、キャッシュからアクセスできなくなります。

Apache Geode は次の有効期限型をサポートしています。

  • 生きる時間 (TTL) : オブジェクトが最後に作成または更新された後、キャッシュ内に保持される時間(秒数)。エントリの場合、作成および書き込み操作ではカウンタはゼロに設定されます。リージョンのカウンタは、リージョンが作成されたとき、およびエントリのカウンタがリセットされたときにリセットされます。

  • アイドルタイムアウト (TTI) : オブジェクトが最後のアクセス後にキャッシュ内に保持される時間(秒数)。オブジェクトのアイドルタイムアウトカウンタは、TTL カウンタがリセットされるたびにリセットされます。さらに、エントリのアイドルタイムアウトカウンタは、get 操作または netSearch を通じてエントリにアクセスされるたびにリセットされます。リージョンのアイドルタイムアウトカウンタは、そのエントリのいずれかのアイドルタイムアウトがリセットされるたびにリセットされます。

これらはそれぞれ、リージョン自体またはリージョン内のエントリに適用できます。Apache Geode の Spring Data には、タイムアウト値と有効期限アクションを指定するための <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 の有効期限 [Apache] (英語) に関するドキュメントを参照してください。

アノテーションベースのデータ有効期限

Spring Data for Apache Geode を使用すると、個々のリージョンエントリ値(言い換えれば、アプリケーションドメインオブジェクトに直接)に対して有効期限ポリシーと設定を定義できます。たとえば、セッションベースのアプリケーションドメインオブジェクトに対して、次のように有効期限ポリシーを定義できます。

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

次の例に示すように、アイドルタイムアウト (TTI) と存続時間 (TTL) の有効期限にそれぞれ @IdleTimeoutExpiration および @TimeToLiveExpiration アノテーションを使用して、リージョンエントリに有効期限型固有の設定を指定することもできます。

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

前の例のように、複数の有効期限アノテーション型が指定されている場合、@IdleTimeoutExpiration と @TimeToLiveExpiration はどちらも汎用の @Expiration アノテーションよりも優先されます。@IdleTimeoutExpiration と @TimeToLiveExpiration は、どちらか一方をオーバーライドすることはありません。むしろ、TTL や TTI など、異なるリージョンエントリ有効期限ポリシーが設定されている場合、これらは互いに補完し合います。

@Expiration ベースのアノテーションはすべて、リージョンエントリの値にのみ適用されます。リージョンの有効期限は、Apache Geode の有効期限アノテーションサポートにおける Spring Data ではサポートされていません。ただし、Apache Geode および Apache Geode の Spring Data では、SDG XML 名前空間を使用してリージョンの有効期限を設定できます。手順は次のとおりです。

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

Apache Geode の @Expiration アノテーションサポートのための Spring Data は、Apache Geode の CustomExpiry [Apache] (英語) インターフェースを使用して実装されています。詳細については、Apache Geode のデータ有効期限設定 [Apache] (英語) に関するドキュメントを参照してください。

Apache Geode の Spring Data AnnotationBasedExpiration クラス (および CustomExpiry 実装) は、SDG @Expiration アノテーションを処理し、リクエストに応じてリージョンエントリの有効期限に適切な有効期限ポリシー構成を適用するロールを担います。

Apache Geode の Spring Data を使用して特定の Apache Geode 領域を構成し、@Expiration ベースのアノテーションが付けられたアプリケーションドメインオブジェクトに有効期限ポリシーを適切に適用するには、次の操作を行う必要があります。

  1. 適切なコンストラクターまたは便利なファクトリメソッドのいずれかを使用して、AnnotationBasedExpiration 型の Spring ApplicationContext クラスに Bean を定義します。アイドルタイムアウト(TTI)や Time-to-Live(TTL)など、特定の有効期限の種類を設定する場合は、AnnotationBasedExpiration クラスのファクトリメソッドのいずれかを次のように使用してください。

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

    代わりにアイドルタイムアウト (TTI) の有効期限を構成するには、forIdleTimeout ファクトリメソッドと <gfe:custom-entry-tti ref="ttiExpiration"/> 要素を使用して TTI を設定します。

  2. (オプション) Spring Data または Apache Geode の @Expiration アノテーションのいずれかを使用して、リージョンに保存されているアプリケーションドメインオブジェクトに有効期限ポリシーとカスタム設定をアノテーションします: @Expiration、@IdleTimeoutExpiration、@TimeToLiveExpiration

  3. (オプション) 特定のアプリケーションドメインオブジェクトに Apache Geode の @Expiration アノテーションの Spring Data がまったく付けられていないが、Apache Geode リージョンが SDG のカスタム AnnotationBasedExpiration クラスを使用してリージョンに格納されているオブジェクトの有効期限ポリシーと設定を決定するように構成されている場合は、次の操作を実行して、AnnotationBasedExpiration Bean に「デフォルト」の有効期限属性を設定できます。

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

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

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

Apache Geode の @Expiration アノテーションの Spring Data では、属性型として String が使用されています。これは、おそらくより適切な、強い型付け(たとえば、「タイムアウト」には int、SDG の「アクション」には ExpirationActionType)ではなく、String が使用されていることにお気づきかもしれません。なぜでしょうか?

Apache Geode の他の機能については、Spring Data のいずれかを入力し、構成の利便性のために Spring のコアインフラストラクチャであるプロパティプレースホルダーと Spring 式言語 (SpEL) 式を活用します。

たとえば、次の例に示すように、開発者は @Expiration アノテーション属性のプロパティプレースホルダーを使用して、有効期限の「タイムアウト」と「アクション」の両方を指定できます。

@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 テストスイートで実証およびテストされています。詳細についてはソースコード [GitHub] (英語) を参照してください。

5.5.10. データの永続性

リージョンは永続化できます。Apache Geode は、永続化が設定されたリージョンに格納されたすべてのデータが、次回リージョンを再作成する際に復元可能な方法でディスクに書き込まれることを保証します。これにより、マシンまたはプロセスに障害が発生した場合、あるいは Apache Geode データノードを正常にシャットダウンして再起動した後でも、データを復元できます。

Apache Geode に対して Spring Data による永続性を有効にするには、次の例に示すように、いずれかの <*-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 は Region 型と一致する必要があり、persistent 属性が明示的に設定されている場合は、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)イベントメッセージング [Apache] (英語) の設定により、リージョンが受信するエントリイベントを制御できます。Apache Geode 用の Spring Data は、REPLICATE および PARTITION リージョンのサブスクリプションポリシーを ALL または CACHE_CONTENT に設定するためのサブ要素 <gfe:subscription/> を提供します。次の例は、サブスクリプションポリシーが CACHE_CONTENT に設定されたリージョンを示しています。

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

5.5.12. 領域

Apache Geode 用の Spring Data は、ローカルリージョンを作成するための専用の local-region 要素を提供します。ローカルリージョンは、その名の通りスタンドアロンであり、他の分散システムメンバーとデータを共有しません。それ以外は、一般的なリージョン設定オプションがすべて適用されます。

次の例は最小限の宣言を示しています (ここでも、この例では、キャッシュを接続するために Spring Data から Apache Geode の XML 名前空間命名規則を使用しています)。

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

上記の例では、ローカルリージョンが作成されます(同じ名前のリージョンがまだ存在しない場合)。リージョン名は Bean の ID(exampleLocalRegion)と同じで、Bean は gemfireCache という名前の Apache Geode キャッシュが存在することを前提としています。

5.5.13. 複製された領域

一般的なリージョン型の 1 つに、REPLICATE リージョン、つまり「レプリカ」があります。簡単に言うと、リージョンが REPLICATE として設定されている場合、そのリージョンをホストするすべてのメンバーは、そのリージョンのエントリのコピーをローカルに保存します。REPLICATE リージョンへの更新は、そのリージョンのすべてのコピーに配信されます。レプリカが作成されると、初期化段階が実行されます。この段階で、レプリカは他のレプリカを検出し、すべてのエントリを自動的にコピーします。1 つのレプリカが初期化されている間も、他のレプリカは引き続き使用できます。

REPLICATE リージョンでは、一般的な設定オプションがすべて利用可能です。Apache Geode の Spring Data には replicated-region 要素が用意されています。以下の例は、最小限の宣言を示しています。

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

詳細については、Apache Geode の分散領域と複製領域 [Apache] (英語) に関するドキュメントを参照してください。

5.5.14. 分割された領域

Apache Geode XML 名前空間の Spring Data は、PARTITION 領域もサポートします。

Apache Geode のドキュメントを引用すると:

“パーティション化されたリージョンとは、そのリージョンをホストするピアサーバー間でデータが分割され、各ピアがデータのサブセットを保存するリージョンです。パーティション化されたリージョンを使用すると、アプリケーションには、リージョン内のすべてのデータを含む単一のマップのような、リージョンの論理ビューが提示されます。このマップへの読み取りまたは書き込みは、操作の対象となるエントリをホストするピアに透過的にルーティングされます。Apache Geode は、ハッシュコードのドメインをバケットに分割します。各バケットは特定のピアに割り当てられますが、クラスター全体のリソース利用率を向上させるために、いつでも別のピアに再配置できます。”

PARTITION リージョンは、partitioned-region 要素を使用して作成されます。その構成オプションは replicated-region と同様ですが、冗長コピー数、最大メモリ量、バケット数、パーティションリゾルバーなど、パーティション固有の機能が追加されています。

次の例は、2 つの冗長コピーを持つ 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 の分割された領域 [Apache] (英語) に関するドキュメントを参照してください。

パーティション化されたリージョン属性

以下の表は、PARTITION リージョン固有の設定オプションの概要を示しています。これらのオプションは、前述の一般的なリージョン設定オプションに加えて利用できるものです。

表 3: パーティション領域属性
名前 値 説明

copies

0..4

高可用性を実現するために、各パーティションにコピーの数を設定します。デフォルトではコピーは作成されず、冗長性はありません。コピーごとに追加のバックアップが提供されますが、その分ストレージ容量が増加します。

colocated-with

有効な領域名

新しく作成された PARTITION リージョンが共存する PARTITION リージョンの名前。

local-max-memory

正の整数

このプロセス内の領域で使用されるメモリの最大量 (メガバイト単位)。

total-max-memory

任意の整数値

すべてのプロセスで領域によって使用されるメモリの最大量 (メガバイト単位)。

partition-listener

Bean 名

パーティションイベントを処理するためにこの領域で使用される PartitionListener の名前。

partition-resolver

Bean 名

この領域でカスタムパーティション分割に使用される PartitionResolver の名前。

recovery-delay

任意の long 値

別のメンバーがクラッシュした後、冗長性を満たすまで既存のメンバーが待機する遅延 (ミリ秒単位)。-1 (デフォルト) は、障害発生後に冗長性が回復されないことを示します。

startup-recovery-delay

任意の long 値

新規メンバーが冗長性を満たすまで待機する遅延時間(ミリ秒)。-1 は、新規メンバーの追加によって冗長性の回復がトリガーされないことを示します。デフォルトでは、新規メンバーが追加されるとすぐに冗長性が回復されます。

5.5.15. クライアント領域

Apache Geode は、データの管理と分散のために、様々なデプロイトポロジをサポートしています。Apache Geode トポロジについては、このドキュメントでは扱いません。簡単にまとめると、Apache Geode がサポートするトポロジは、ピアツーピア(P2P)、クライアントサーバー、ワイドエリアネットワーク(WAN)に分類できます。最後の 2 つの構成では、キャッシュサーバーに接続するクライアントリージョンを宣言するのが一般的です。

Spring Data と Apache Geode は、クライアントキャッシュ要素である client-region と pool を通じて、それぞれの構成に特化したサポートを提供します。名前が示すように、client-region はクライアントリージョンを定義し、pool は様々なクライアントリージョンで使用および共有される接続のプールを定義します。

次の例は、一般的なクライアントリージョン構成を示しています。

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

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

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

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

他のリージョン型と同様に、client-region は CacheListener インスタンスに加え、CacheLoader と CacheWriter もサポートします。また、ロケータまたはサーバーのセットに接続するために、接続 Pool が必要です。各クライアントリージョンは独自の Pool を持つことも、同じ Pool を共有することもできます。プールが指定されていない場合は、"DEFAULT" プールが使用されます。

上の例では、Pool にロケーターが設定されています。ロケーターは、分散システム内のキャッシュサーバーとピアデータメンバーを検出するために使用される独立したプロセスであり、本番システムに推奨されます。また、server 要素を使用して、Pool を 1 つ以上のキャッシュサーバーに直接接続するように設定することも可能です。

クライアント、特に Pool に設定するオプションの完全なリストについては、Apache Geode スキーマ ( "Spring Data for Apache Geode Schema" ) の Spring Data と、クライアント / サーバー構成 [Apache] (英語) に関する Apache Geode のドキュメントを参照してください。

クライアントの関心

ネットワークトラフィックを最小限に抑えるため、各クライアントは独自の「関心」ポリシーを個別に定義し、Apache Geode に実際に必要なデータを指定できます。Apache Geode の Spring Data では、各クライアントリージョンごとに「関心」を個別に定義できます。キーベースと正規表現ベースの両方の関心型がサポートされています。

次の例は、キーベースと正規表現ベースの両方の 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> キーと正規表現要素は、3 つの属性 (durable、receive-values、result-policy) をサポートします。

durable は、クライアントがクラスタ内の 1 つ以上のサーバーに接続した際にクライアント用に作成された「インタレスト」ポリシーとサブスクリプションキューが、クライアントセッション間で維持されるかどうかを示します。クライアントが離れてから再び接続した場合、クライアントが切断されている間、サーバー上のクライアント用 durable サブスクリプションキューが維持されます。クライアントが再接続すると、クラスタ内のサーバーから切断されている間に発生したイベントがクライアントに送信されます。

クラスター内のサーバー上のサブスクリプションキューは、クライアントで定義された接続の Pool ごとに保持され、その Pool のサブスクリプションも「有効」になっています。サブスクリプションキューは、クライアントに送信されたイベントを格納 (および場合によっては統合) するために使用されます。サブスクリプションキューが永続的である場合、サブスクリプションキューはクライアントセッション (つまり、接続) 間で、指定されたタイムアウトまで存続する可能性があります。クライアントが指定された時間内に戻らない場合、クラスター内のサーバーのリソース消費を削減するため、クライアントプールサブスクリプションキューは破棄されます。サブスクリプションキューが durable でない場合、クライアントが切断すると直ちに破棄されます。クライアントが切断中に受信したイベントを受信するか、再接続後に最新のイベントのみを受信するかを決定する必要があります。

receive-values 属性は、作成イベントおよび更新イベントでエントリ値を受信するかどうかを示します。true の場合、値は受信されます。false の場合、無効化イベントのみが受信されます。

最後に、「結果ポリシー」は 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 のクライアントからサーバーへのイベント配信 [Apache] (英語) に関するドキュメントを参照してください。

5.5.16. JSON サポート

Apache Geode は、リージョン内の JSON ドキュメントのキャッシュをサポートし、保存されている JSON ドキュメントを Apache Geode OQL(オブジェクトクエリ言語)を使用してクエリする機能も備えています。JSON ドキュメントは、JSONFormatter [Apache] (英語) クラスを使用して JSON ドキュメント(String)との変換を行うことで、内部的には PdxInstance [Apache] (英語) 型として保存されます。

Apache Geode 用の Spring Data は、AOP コンポーネントが適切なプロキシ領域操作をアドバイスできるようにする <gfe-data:json-region-autoproxy/> 要素を提供します。これにより、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() Region 操作の結果は、設定された Region に合わせて変換されます。これは、ローカルメモリに並列データ構造を作成することで行われます。大規模なコレクションでは、この処理によって大きなオーバーヘッドが発生する可能性があります。これらの Region 操作の自動変換を無効にする場合は、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"/>

この機能は、テンプレートが Spring Bean として宣言されている場合、GemfireTemplate 演算でもシームレスに動作します。現在、ネイティブの QueryService 演算はサポートされていません。

5.6. インデックスの設定

Apache Geode を使用すると、Region データにインデックス (複数形は indexes とも呼ばれます) を作成して、OQL (Object Query Language) クエリのパフォーマンスを向上させることができます。

Apache Geode の Spring Data では、次の例に示すように、インデックスは index 要素で宣言されます。

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

Apache Geode の XML スキーマ(SDG XML 名前空間とも呼ばれます)の Spring Data では、index Bean 宣言は Apache Geode のネイティブ cache.xml とは異なり、リージョンにバインドされていません。むしろ、<gfe:cache> 要素と同様に、トップレベル要素です。これにより、作成されたばかりかすでに存在するかにかかわらず、任意のリージョンに任意の数のインデックスを宣言できます。これは、Apache Geode のネイティブ cache.xml 形式からの大幅な改善です。

Index には名前が必要です。Index には name 属性を使用して明示的に名前を付けることができます。そうでない場合は、index の Bean 定義の Bean 名(つまり、id 属性の値)が Index 名として使用されます。

expression 句と from 句は Index 句の主要な構成要素であり、インデックス付けするデータ(つまり、from 句で識別されるリージョン)と、そのデータのインデックス付けに使用される条件(つまり、expression)を指定します。expression 句は、リージョンに格納されているオブジェクトのクエリと検索に使用されるアプリケーション定義の OQL クエリの述語で使用されるアプリケーションドメインオブジェクトフィールドに基づいて作成する必要があります。

lastName プロパティを持つ次の例を考えてみましょう。

@Region("Customers")
class Customer {

  @Id
  Long id;

  String lastName;
  String firstName;

  ...
}

ここで、Customer オブジェクトを照会するためのアプリケーション定義の SDG リポジトリを持つ次の例を考えてみましょう。

interface CustomerRepository extends GemfireRepository<Customer, Long> {

  Customer findByLastName(String lastName);

  ...
}

SDG リポジトリファインダー / クエリメソッドにより、次の OQL ステートメントが生成され、実行されます。

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

次のようなステートメントを使用して Index を作成する必要があります。

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

from 句は有効な既存のリージョンを参照する必要があり、Index 句はリージョンに適用されます。これは Spring Data for Apache Geode に固有のものではなく、Apache Geode の機能です。

Index type は、Apache Geode の IndexType (Javadoc) 列挙に対して Spring Data によって定義された 3 つの列挙値 (FUNCTIONAL、HASH、PRIMARY_KEY) のいずれかになります。

列挙された値はそれぞれ、実際の Index が作成(または「定義」)される際に呼び出される QueryService [Apache] (英語) または create[|Key|Hash]Index メソッドのいずれかに対応します。インデックスの「定義」については次のセクションで詳しく説明します。たとえば、IndexType が PRIMARY_KEY の場合、QueryService.createKeyIndex(..) [Apache] (英語) が呼び出されて KEY または Index が作成されます。

デフォルトは FUNCTIONAL で、QueryService.createIndex(..) メソッドのいずれかが呼び出されます。オプションの全セットについては、Spring Data for Apache Geode XML スキーマを参照してください。

Apache Geode でのインデックス作成の詳細については、Apache Geode のユーザーガイドの "インデックスの操作 (英語) " を参照してください。

5.6.1. インデックスの定義

Spring コンテナーの初期化時に Spring Data によって Apache Geode 用に Index Bean 定義が処理されるときに事前にインデックスを作成することに加えて、次のように、define 属性を使用して、アプリケーションインデックスを作成する前にすべて定義することもできます。

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

define が true に設定されている場合(デフォルトは false)、その時点では Index は実際には作成されません。すべての「定義済み」インデックスは、Spring の ApplicationContext が「リフレッシュ」されたとき、つまり Spring コンテナーによって ContextRefreshedEvent が発行されたときに、一度に作成されます。Apache Geode の Spring Data は、ContextRefreshedEvent を待機する ApplicationListener として自身を登録します。Apache Geode の Spring Data は、発行されると QueryService.createDefinedIndexes() [Apache] (英語) を呼び出します。

インデックスを定義して一度に作成すると、インデックス作成時の速度と効率が向上します。

詳細は "複数のインデックスを一度に作成する (英語) " を参照してください。

5.6.2. IgnoreIfExists および Override

Apache Geode、Index 構成オプションのうち、特に注目すべきは Spring Data と ignoreIfExists および override の 2 つです。

これらのオプションは、それぞれ、Apache Geode の XML 名前空間の Spring Data の <gfe:index> 要素の ignore-if-exists 属性と override 属性に対応します。

これらのオプションを使用する前に、何をしようとしているのかをしっかりと理解していることを確認してください。これらのオプションは、実行時にアプリケーションが消費するパフォーマンスやリソース(メモリなど)に影響を与える可能性があります。そのため、SDG ではこれらのオプションは両方ともデフォルトで無効(false に設定)になっています。
これらのオプションは、Apache Geode の Spring Data でのみ使用可能であり、Apache Geode の既知の制限を回避するために存在します。Apache Geode には同等のオプションや機能はありません。

各オプションの動作は大きく異なり、スローされる Apache Geode Index 例外の種類によって完全に異なります。つまり、Apache Geode インデックス型例外がスローされない場合は、どちらのオプションも効果がありません。これらのオプションは、様々な、時には不明瞭な理由で発生する可能性のある Apache Geode IndexExistsException および IndexNameConflictException インスタンスを特に処理することを目的としています。これらの例外の原因は次のとおりです。

Apache Geode の Spring Data のデフォルトの動作は、常にフェイルファストです。そのため、Index  例外はどちらもデフォルトでは「処理」されません。これらの Index 例外は SDG GemfireIndexException にラップされ、再スローされます。Apache Geode の Spring Data でこれらの例外を処理したい場合は、Index Bean 定義オプションのいずれかを true に設定してください。

IgnoreIfExists は常に Override よりも優先されます。主な理由は、両方の例外的なケースで「既存の」 Index を返すため、使用するリソースが少なくなるからです。

IgnoreIfExists の動作

IndexExistsException がスローされ、ignoreIfExists が true (または <gfe:index ignore-if-exists="true">) に設定されると、この index Bean 定義または宣言によって作成された Index は単に無視され、既存の Index が返されます。

index Bean の定義は SDG ではなく Apache Geode 自体によって決定されるため同じであるため、既存の Index を返してもほとんど影響はありません。

しかし、これは、index Bean の定義または宣言で指定された「名前」を持つ Index が、Apache Geode の観点から(つまり、QueryService.getIndexes() [Apache] (英語) の観点から)実際には存在しないことを意味します。クエリヒントを使用する OQL クエリ文を記述する際には注意が必要です。特に、無視されるアプリケーション Index を参照するクエリヒントには注意が必要です。これらのクエリヒントは変更する必要があります。

IndexNameConflictException がスローされ、ignoreIfExists が true (または <gfe:index ignore-if-exists="true">) に設定されると、この index Bean 定義または宣言によって作成された Index も無視され、IndexExistsException がスローされたときと同様に、「既存の」 Index が再度返されます。

しかし、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 から Apache Geode への変換は、Apache Geode の API を使用することでのみ実現できます。まず既存の Index を削除し、次に新しい名前で Index を再作成します。削除またはそれに続く作成のいずれかの呼び出しが失敗する可能性があります。両方のアクションをアトミックに実行し、どちらかが失敗した場合にこの結合操作をロールバックする方法はありません。

ただし、成功した場合、ignoreIfExists オプションを使用した場合と同じ問題が発生します。古い Index を名前で参照するクエリヒントを使用している既存の OQL クエリ文はすべて変更する必要があります。

IndexNameConflictException がスローされ、override が true (または <gfe:index override="true">)に設定されると、既存の Index が再定義される可能性があります。「潜在的に」と言うのは、IndexNameConflictException がスローされた際に、同じ名前を持つ既存の Index が全く同じ定義と名前を持つ可能性があるためです。

そうであれば、SDG は賢く、override であっても既存の Index をそのまま返します。名前と定義が全く同じなので、この動作に問題はありません。もちろん、SDG がこれを実現できるのは、Apache Geode の API に依存する既存の Index を見つけられる場合のみです。Index が見つからない場合は何も起こらず、IndexNameConflictException をラップする SDG GemfireIndexException がスローされます。

ただし、既存の Index の定義が異なる場合、SDG は index の Bean 定義で指定された Index の定義を使用して Index を再作成しようとします。これが目的の Index であること、index の Bean 定義が期待値とアプリケーション要件を満たしていることを確認してください。

IndexNameConflictExceptions は実際にはどのように発生するのでしょうか ?

IndexExistsExceptions がスローされることは、特に複数の設定ソース(Apache Geode 用の Spring Data、Apache Geode Cluster Config、Apache Geode ネイティブの cache.xml、API など)を使用して Apache Geode を設定している場合、それほど珍しいことではありません。必ず 1 つの設定方法を選択し、それを使い続けることをお勧めします。

しかし、IndexNameConflictException はいつスローされるのでしょうか ?

具体的な例として、PARTITION リージョン(PR)上に Index が定義されている場合が挙げられます。PARTITION リージョン上に Index (たとえば X)が定義されている場合、Apache Geode は、同じ PARTITION リージョン(つまり "X" )をホストするクラスター内の他のピアメンバーに Index の定義(および名前)を配布します。この Index 定義の配布、およびピアメンバーによる Index の作成は、必要に応じて(つまり、同じ PR をホストするピアメンバーによって)非同期的に実行されます。

この期間中、保留中の PR Indexes は、QueryService.getIndexes(:Region) [Apache] (英語) による QueryService.getIndexes() [Apache] (英語) の呼び出しや、QueryService.getIndex(:Region, indexName:String) [Apache] (英語) による呼び出しなど、Apache Geode によって識別できない可能性があります。

その結果、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 の構成

Apache Geode 用の Spring Data は、次の例に示すように、disk-store 要素を介して DiskStore の構成と作成をサポートします。

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

DiskStore インスタンスは、リージョンによってファイルシステムの永続バックアップ、削除されたエントリのオーバーフロー、WAN ゲートウェイの永続バックアップに使用されます。複数の Apache Geode コンポーネントが同じ DiskStore を共有できます。さらに、前の例に示すように、単一の DiskStore に対して複数のファイルシステムディレクトリを定義できます。

永続化とオーバーフロー [Apache] (英語) と DiskStore インスタンスの構成オプションの詳細な説明については、Apache Geode のドキュメントを参照してください。

5.8. スナップショットサービスの構成

Apache Geode 用の Spring Data は、Apache Geode のスナップショットサービス (英語) を使用してキャッシュおよびリージョンスナップショットをサポートします。すぐに使用可能なスナップショットサービスサポートには、Apache Geode のキャッシュ [Apache] (英語) および領域 [Apache] (英語) スナップショットサービス API の使用を簡素化する便利な機能がいくつか用意されています。

Apache Geode ドキュメント (英語) の説明にあるように、スナップショットを使用するとキャッシュデータを保存し、後でリロードすることができます。これは、本番環境からステージング環境やテスト環境へデータを移動し、制御されたコンテキストでデータ関連の課題を再現する場合など、環境間でデータを移動する際に役立ちます。Spring Data と Apache Geode のスナップショットサービスサポートを Spring の Bean 定義プロファイル (英語) と組み合わせることで、必要に応じて環境固有のスナップショットデータをロードできます。

Apache Geode の Apache Geode スナップショットサービスのサポートのための Spring Data は、<gfe-data> XML 名前空間の <gfe-data:snapshot-service> 要素から始まります。

たとえば、次のように、いくつかのスナップショットのインポートとデータのエクスポート定義を使用して、キャッシュ全体のスナップショットをロードおよび保存するように定義できます。

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

インポートとエクスポートは好きなだけ定義できます。インポートのみ、またはエクスポートのみを定義することもできます。ファイルの場所とディレクトリパスは、JVM プロセスの作業ディレクトリである Spring Data for Apache Geode アプリケーションを基準とした絶対パスまたは相対パスで指定できます。

上記の例は非常にシンプルで、ここで定義されているスナップショットサービスは、デフォルト名 gemfireCache (キャッシュの設定で説明されているとおり)を持つ Apache Geode キャッシュインスタンスを参照します。キャッシュ 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 属性が指定されている場合、Apache Geode の SnapshotServiceFactoryBean に対する Spring Data は、region-ref 属性値を Spring コンテナーで定義されたリージョン Bean に解決し、RegionSnapshotService [Apache] (英語) を作成します。スナップショットのインポートとエクスポートの定義は同じように機能します。ただし、エクスポートでは location がファイルを参照する必要があります。

Apache Geode は、インポートされたスナップショットファイルが参照される前に実際に存在していることを厳密に確認します。エクスポートの場合、Apache Geode がスナップショットファイルを作成します。エクスポート用のスナップショットファイルがすでに存在する場合、データは上書きされます。
Apache Geode 用の Spring Data には、<gfe-data:snapshot-service> 要素に suppress-import-on-init 属性が含まれており、これにより、設定されたスナップショットサービスが初期化時にキャッシュまたはリージョンへのデータのインポートを試行するのを抑制できます。これは、たとえば、あるリージョンからエクスポートされたデータを別のリージョンのインポートに利用する場合などに便利です。

5.8.1. スナップショットの場所

キャッシュベースのスナップショットサービス (つまり、CacheSnapshotService [Apache] (英語) ) では、通常、CacheSnapshotService API のオーバーロードされた load [Apache] (英語) メソッドが示すように、個々のスナップショットファイルではなく、ロードするすべてのスナップショットファイルを含むディレクトリを渡します。

もちろん、オーバーロードされた load(:File[], :SnapshotFormat, :SnapshotOptions) メソッドを使用して、どのスナップショットファイルを Apache Geode キャッシュにロードするかを指定することもできます。

ただし、Spring Data for Apache Geode では、一般的な開発者ワークフローとして、1 つの環境からデータを抽出して複数のスナップショットファイルにエクスポートし、それらすべてを zip ファイルに圧縮してから、その zip ファイルを別の環境に簡単に移動してインポートするということが考えられることを認識しています。

Apache Geode 用の Spring Data では、次のように、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>

Apache Geode 用の Spring Data は、提供された zip ファイルを簡単に抽出し、ディレクトリのインポート (ロード) として扱います。

5.8.2. スナップショットフィルター

複数のスナップショットのインポートとエクスポートを定義することの真価は、スナップショットフィルターの使用によって発揮されます。スナップショットフィルターは Apache Geode の SnapshotFilter [Apache] (英語) インターフェースを実装し、インポート時にリージョンに含めるエントリとエクスポート時にスナップショットに含めるエントリをフィルタリングするために使用されます。

Apache Geode の Spring Data では、次の例に示すように、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 [Apache] (英語) インターフェースとコンポジット [Wikipedia] (英語) ソフトウェア設計パターンを実装しています。

簡単に言えば、コンポジット [Wikipedia] (英語) ソフトウェア設計パターンを使用すると、同じ型の複数のオブジェクトを作成し、その集合をオブジェクト型の単一のインスタンスとして扱うことができます。これは強力で便利な抽象化です。

ComposableSnapshotFilter には、and と or という 2 つのファクトリメソッドがあります。これらのメソッドは、それぞれ 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 アプリケーション内から、インポートまたはエクスポートのいずれかの目的で、イベントベースの定期的なスナップショットをトリガーすることもできます。

この目的のために、Apache Geode の Spring Data は、それぞれインポートとエクスポート用に Spring の ApplicationEvent (Javadoc) クラスを継承した 2 つの追加の Spring アプリケーションイベント (ImportSnapshotApplicationEvent と ExportSnapshotApplicationEvent) を定義します。

2 つのアプリケーションイベントは、Apache Geode キャッシュ全体または個々の Apache Geode リージョンを対象にすることができます。これらのクラスのコンストラクターは、オプションのリージョンパス名(例: /Example)と、0 個以上の SnapshotMetadata インスタンスを受け入れます。

SnapshotMetadata 配列は、スナップショットアプリケーションイベントが明示的に SnapshotMetadata を提供しない場合に使用される、<gfe-data:snapshot-import> および <gfe-data:snapshot-export> サブ要素によって定義されたスナップショットメタデータをオーバーライドします。個々の SnapshotMetadata インスタンスは、独自の location および filters プロパティを定義できます。

Spring ApplicationContext で定義されているすべてのスナップショットサービス Bean は、スナップショットのインポートおよびエクスポートアプリケーションイベントを受信します。ただし、インポートおよびエクスポートイベントを処理するのは、対応するスナップショットサービス Bean のみです。

定義されたスナップショットサービス Bean が RegionSnapshotService であり、そのリージョン参照 (region-ref 属性によって決定) がスナップショットアプリケーションイベントによって指定されたリージョンのパス名と一致する場合、リージョンベースの [Import|Export]SnapshotApplicationEvent は一致します。

キャッシュベースの [Import|Export]SnapshotApplicationEvent (つまり、リージョンパス名のないスナップショットアプリケーションイベント) は、すべてのスナップショットサービス Bean (RegionSnapshotService Bean を含む) をトリガーして、それぞれインポートまたはエクスポートを実行します。

次のように、Spring の ApplicationEventPublisher (Javadoc) インターフェースを使用して、アプリケーションからスナップショットのインポートおよびエクスポートアプリケーションイベントを起動できます。

@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 関数の実装、登録、実行のためのアノテーションサポートを提供します。

Apache Geode の Spring Data は、リモート関数実行用の Apache Geode 関数 [Apache] (英語) を登録するための XML 名前空間サポートも提供します。

関数実行フレームワークの詳細については、Apache Geode のドキュメント [Apache] (英語) を参照してください。

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 分散システムを同期させる手段を提供します。Apache Geode 用の Spring Data は、以下の例に示すように、WAN ゲートウェイを構成するための XML 名前空間サポートを提供します。

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 のドキュメント [Apache] (英語) を参照してください。

6. アノテーションを使用して Spring コンテナーで Apache Geode をブートストラップする

Apache Geode 用の Spring Data (SDG) 2.0 は、Spring コンテナーを使用して Apache Geode を構成およびブートストラップするための新しいアノテーションベースの構成モデルを導入します。

Spring コンテキストでの Apache Geode の構成にアノテーションベースのアプローチを導入する主な目的は、Spring アプリケーション開発者が可能な限り迅速かつ簡単に 起動して実行できるようにすることです。

さあ、始めましょう!

さらに早く開始したい場合は、クイックスタートセクションを参照してください。

6.1. 導入

Apache Geode は、設定プロパティ [Apache] (英語) やさまざまな設定オプションが多数存在するため、正しく設定して使用するのは難しい場合があります。

サポートされているトポロジが異なるため、さらに複雑になります。

アノテーションベースの構成モデルは、これらすべてとそれ以上のものを簡素化することを目的としています。

アノテーションベースの設定モデルは、Apache Geode の XML 名前空間に Spring Data を使用する XML ベースの設定の代替手段です。XML を使用すると、設定には gfe XML スキーマを使用し、データアクセスには gfe-data XML スキーマを使用できます。詳細については、"Spring コンテナーを使用した Apache Geode のブートストラップ" を参照してください。

SDG 2.0 時点では、アノテーションベースの構成モデルは、Apache Geode の WAN コンポーネントとトポロジの構成をまだサポートしていません。

Spring Boot と同様に、Apache Geode のアノテーションベースの設定モデルである Spring Data は、Apache Geode を利用するための、設定よりも規約を重視する独自のアプローチとして設計されました。実際、このアノテーションベースの設定モデルは、Spring Boot だけでなく、他のいくつかの Spring および Spring Data プロジェクトからも影響を受けています。

慣例に従い、すべてのアノテーションはすべての設定属性に対して、適切かつ妥当なデフォルト値を提供します。特定のアノテーション属性のデフォルト値は、同じ設定プロパティに対して Apache Geode で提供されるデフォルト値と直接対応します。

その目的は、機能やサービスを使用するために多数のプロパティを不必要に構成する必要なく、Spring、@Configuration、@SpringBootApplication クラスに適切なアノテーションを宣言することで、Apache Geode 機能や埋め込みサービスを有効にできるようにすることです。

繰り返しますが、迅速かつ簡単に 開始することが主な目的です。

ただし、必要に応じて Apache Geode の構成メタデータと動作をカスタマイズするオプションが用意されており、Apache Geode のアノテーションベースの構成のための Spring Data は静かに後退します。調整したい構成属性を指定するだけで済みます。また、このドキュメントの後半で説明するように、アノテーションを使用して Apache Geode の機能または組み込みサービスを構成する方法はいくつかあります。

新しい SDG Java Annotations はすべて org.springframework.data.gemfire.config.annotation パッケージに含まれています。

6.2. Spring を使用した Apache Geode アプリケーションの構成

アプリケーションクラスに @SpringBootApplication をアノテーションすることから始まるすべての Spring Boot アプリケーションと同様に、Spring Boot アプリケーションは、次の 3 つの主要なアノテーションのいずれかを宣言することで簡単に Apache Geode キャッシュアプリケーションになることができます。

  • @ClientCacheApplication

  • @PeerCacheApplication

  • @CacheServerApplication

これら 3 つのアノテーションは、Spring アプリケーション開発者が Apache Geode を操作する際の出発点となります。

これらのアノテーションの背後にある意図を理解するには、Apache Geode で作成できるキャッシュインスタンスにはクライアントキャッシュとピアキャッシュの 2 種類があることを理解する必要があります。

Spring Boot アプリケーションを ClientCache インスタンスを持つ Apache Geode キャッシュクライアントとして構成できます。ClientCache インスタンスは、アプリケーションのデータ管理に使用される既存の Apache Geode サーバークラスターと通信できます。クライアントサーバートポロジは、Apache Geode を使用する際に最も一般的に採用されるシステムアーキテクチャです。Spring Boot アプリケーションを @ClientCacheApplication アノテーションを付与するだけで、ClientCache インスタンスを持つキャッシュクライアントにすることができます。

あるいは、Spring Boot アプリケーションは Apache Geode クラスタのピアメンバーになることができます。つまり、アプリケーション自体は、データを管理するサーバークラスタ内の単なる別のサーバーです。Spring Boot アプリケーションは、アプリケーションクラスに @PeerCacheApplication アノテーションを付与すると、「埋め込み型」のピア Cache インスタンスを作成します。

拡張により、ピアキャッシュアプリケーションは CacheServer としても機能し、キャッシュクライアントがサーバーに接続してデータアクセス操作を実行できるようになります。これは、アプリケーションクラスに @PeerCacheApplication ではなく @CacheServerApplication をアノテーションすることで実現されます。これにより、キャッシュクライアントが接続できる CacheServer に加えて、ピア Cache インスタンスが作成されます。

Apache Geode サーバーは、デフォルトでは必ずしもキャッシュサーバーではありません。つまり、サーバーであるというだけで、必ずしもキャッシュクライアントにサービスを提供するように設定されているわけではありません。Apache Geode サーバーは、クラスタ内の他のピアメンバーがデータ管理に加えてクライアントにサービスを提供するように設定されている場合でも、クライアントにサービスを提供せずにデータを管理するクラスタのピアメンバー (データノード) になることができます。また、クラスタ内の特定のピアメンバーを、データを保存せず、CacheServers としてクライアントにサービスを提供するプロキシとして機能するデータアクセサー [Apache] (英語) と呼ばれる非データノードとして設定することも可能です。Apache Geode はさまざまなトポロジとクラスタ構成をサポートしていますが、このドキュメントの範囲外です。

たとえば、Spring Boot キャッシュクライアントアプリケーションを作成する場合は、次の作業から始めます。

Spring ベースの Apache Geode ClientCache アプリケーション
@SpringBootApplication
@ClientCacheApplication
class ClientApplication { .. }

または、組み込みピア Cache インスタンスを持つ Spring Boot アプリケーションを作成し、アプリケーションが Apache Geode によって形成されるクラスター (分散システム) のサーバーおよびピアメンバーとなる場合は、次の内容から始めます。

Spring ベースの Apache Geode 組み込みピア Cache アプリケーション
@SpringBootApplication
@PeerCacheApplication
class ServerApplication { .. }

あるいは、次のように、@PeerCacheApplication の代わりに @CacheServerApplication アノテーションを使用して、埋め込みピア Cache インスタンスと、localhost 上で実行され、デフォルトのキャッシュサーバーポート 40404 をリッスンする CacheServer の両方を作成することもできます。

Spring ベースの Apache Geode 組み込みピア Cache アプリケーションと CacheServer
@SpringBootApplication
@CacheServerApplication
class ServerApplication { .. }

6.3. クライアント / サーバーアプリケーションの詳細

クライアントが Apache Geode クラスター内のサーバーに接続し、通信する方法は複数あります。最も一般的かつ推奨される方法は、Apache Geode ロケーターを使用することです。

キャッシュクライアントは、CacheServer に直接接続する代わりに、Apache Geode クラスタ内の 1 つ以上のロケータに接続できます。直接 CacheServer 接続ではなくロケータを使用する利点は、ロケータがクライアントが接続しているクラスタに関するメタデータを提供することです。このメタデータには、必要なデータが格納されているサーバーや、負荷が最も少ないサーバーなどの情報が含まれます。クライアント Pool はロケータと連携して、CacheServer がクラッシュした場合のフェイルオーバー機能も提供します。クライアント Pool で PARTITION リージョン(PR)シングルホップ機能を有効にすると、クライアントはリクエストされ、必要なデータが格納されているサーバーに直接ルーティングされます。
ロケータはクラスタ内のピアメンバーでもあります。ロケータは、実際には Apache Geode ノードのクラスタを構成する要素です。つまり、ロケータによって接続されたすべてのノードはクラスタ内のピアであり、新しいメンバーはロケータを使用してクラスタに参加し、他のメンバーを見つけます。

デフォルトでは、Apache Geode は localhost 上で動作する CacheServer に接続された "DEFAULT" Pool を設定し、ClientCache インスタンスの作成時にポート 40404 をリッスンします。CacheServer はポート 40404 をリッスンし、すべてのシステム NIC からの接続を受け入れます。クライアントサーバートポロジを使用するために特別な操作は必要ありません。サーバー側の Spring Boot アプリケーションに @CacheServerApplication を、クライアント側の Spring Boot アプリケーションに @ClientCacheApplication をアノテーションするだけで準備完了です。

ご希望であれば、Gfsh の start server コマンドでサーバーを起動することもできます。Spring Boot(@ClientCacheApplication)は、起動方法に関わらずサーバーに接続できます。ただし、適切にアノテーションされた Spring Boot アプリケーションクラスの方がはるかに直感的でデバッグも容易であるため、Spring Data for Apache Geode アプローチを使用してサーバーを設定および起動することをお勧めします。

アプリケーション開発者としては、次の例に示すように、Apache Geode によって設定された "DEFAULT" Pool をカスタマイズして、1 つ以上のロケータに接続できるようにしたいと考えるでしょう。

ロケータを使用した Spring ベースの Apache Geode ClientCache アプリケーション
@SpringBootApplication
@ClientCacheApplication(locators = {
    @Locator(host = "boombox" port = 11235),
    @Locator(host = "skullbox", port = 12480)
})
class ClientApplication { .. }

locators 属性に加えて、@ClientCacheApplication アノテーションには servers 属性もあります。servers 属性は、必要に応じてキャッシュクライアントが 1 つ以上のサーバーに直接接続できるようにする、1 つ以上のネストされた @Server アノテーションを指定するために使用できます。

locators 属性または servers 属性のいずれかを使用できますが、両方は使用できません (これは Apache Geode によって強制されます)。

@EnablePool および @EnablePools アノテーションを使用して、追加の Pool インスタンス (@ClientCacheApplication アノテーションを使用して ClientCache インスタンスが作成された場合に Apache Geode によって提供される "DEFAULT" Pool 以外) を構成することもできます。

@EnablePools は、複数のネストされた @EnablePool アノテーションを単一のクラスに集約する複合アノテーションです。Java 8 以前では、単一のクラスに同じ型のアノテーションを複数宣言することはできません。

次の例では、@EnablePool および @EnablePools アノテーションを使用しています。

複数の名前付き Pools を使用した Spring ベースの Apache Geode ClientCache アプリケーション
@SpringBootApplication
@ClientCacheApplication(logLevel = "info")
@EnablePool(name = "VenusPool", servers = @Server(host = "venus", port = 48484),
    min-connections = 50, max-connections = 200, ping-internal = 15000,
    prSingleHopEnabled = true, readTimeout = 20000, retryAttempts = 1,
    subscription-enable = true)
@EnablePools(pools = {
    @EnablePool(name = "SaturnPool", locators = @Locator(host="skullbox", port=20668),
        subsription-enabled = true),
    @EnablePool(name = "NeptunePool", severs = {
            @Server(host = "saturn", port = 41414),
            @Server(host = "neptune", port = 42424)
        }, min-connections = 25))
})
class ClientApplication { .. }

name 属性は、@EnablePool アノテーションの唯一の必須属性です。後述のとおり、name 属性の値は、Spring コンテナーで作成された Pool (Bean)の名前と、対応する設定プロパティを参照するために使用される名前の両方に対応しています。また、Apache Geode によって登録および使用される Pool の名前でもあります。

同様に、サーバー上で、クライアントが接続できる複数の CacheServers を次のように構成できます。

複数の名前付き CacheServers を使用した Spring ベースの Apache Geode CacheServer アプリケーション
@SpringBootApplication
@CacheSeverApplication(logLevel = "info", autoStartup = true, maxConnections = 100)
@EnableCacheServer(name = "Venus", autoStartup = true,
    hostnameForClients = "venus", port = 48484)
@EnableCacheServers(servers = {
    @EnableCacheServer(name = "Saturn", hostnameForClients = "saturn", port = 41414),
    @EnableCacheServer(name = "Neptune", hostnameForClients = "neptune", port = 42424)
})
class ServerApplication { .. }
@EnablePools と同様に、@EnableCacheServers は複数の @EnableCacheServer アノテーションを単一のクラスに集約するための複合アノテーションです。繰り返しになりますが、Java 8 以前では、単一のクラスに同じ型のアノテーションを複数宣言することはできません。

注意深いリーダーならお気づきかもしれませんが、すべてのケースにおいて、ホスト名、ポート、設定関連のアノテーション属性にハードコードされた値が指定されています。これは、アプリケーションが開発環境から QA 環境、ステージング環境、本番環境へと昇格・デプロイされる際に、理想的とは言えません。

次のセクションでは、実行時に決定される動的な構成を処理する方法について説明します。

6.4. ロケーターの構成とブートストラップ

Apache Geode キャッシュアプリケーションのほかに、Apache Geode ロケーターアプリケーションも作成できます。

Apache Geode ロケータは、ノードが Apache Geode クラスタにピアメンバーとして参加できるようにする JVM プロセスです。ロケータは、クライアントがクラスタ内のサーバーを検出できるようにもします。ロケータは、クラスタ内のメンバー間で負荷を均等に分散するためのメタデータをクライアントに提供し、シングルホップのデータアクセス操作を可能にするなど、様々な機能を提供します。

ロケータに関する詳細な説明は、このドキュメントの範囲外です。ロケータとクラスタにおけるそのロールの詳細については、Apache Geode ユーザーガイド [Apache] (英語) を参照してください。

スタンドアロンの Locator プロセスを構成およびブートストラップするには、次の手順を実行します。

Spring Boot、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 プロパティのいずれかを設定してください。

次に、次のように、Spring で構成およびブートストラップされた、ロケーター (1 つまたは複数) が参加しているクラスター内で 1 つ以上の Apache Geode ピアキャッシュメンバーを起動できます。

Spring Boot、Apache Geode、CacheServer アプリケーションは、localhost、ポート 12345 のロケータによって参加しました。
@SpringBootApplication
@CacheServerApplication(locators = "localhost[12345]")
class ServerApplication { ... }

繰り返しになりますが、上記の Locator で結合された ServerApplication クラスは、必要な数だけ作成できます。メンバーの名前が一意であることを確認するだけです。

@LocatorApplication は、スタンドアロンの Apache Geode Locator アプリケーションプロセスの設定とブートストラップに使用されます。このプロセスは Locator のみに使用できます。キャッシュインスタンスを使用して Locator を起動しようとすると、SDG はエラーをスローします。

埋め込まれたロケータと同時にキャッシュインスタンスを開始する場合は、代わりに @EnableLocator アノテーションを使用する必要があります。

開発段階では組み込みのロケーターを起動するのが便利です。ただし、高可用性を実現するために、本番環境ではスタンドアロンのロケータープロセスを実行することを強くお勧めします。クラスター内のすべてのロケーターがダウンした場合、クラスターはそのまま残りますが、新しいメンバーはクラスターに参加できなくなります。これは、需要を満たすために線形にスケールアウトする上で重要です。

詳細については、埋め込みロケーターの設定のセクションを参照してください。

6.5. Configurers を使用したランタイム構成

アノテーションベースの構成モデルを設計する際のもう 1 つのゴールは、アノテーション属性の型の安全性を維持することでした。例: 構成属性を int (ポート番号など) として表現できる場合、属性の型は int である必要があります。

残念ながら、これは実行時に動的かつ解決可能な構成を実現するものではありません。

Spring の優れた機能の一つは、Spring コンテナー内の Bean を設定する際に、設定メタデータのプロパティまたは属性でプロパティプレースホルダと SpEL 式を使用できることです。しかし、これを行うにはすべてのアノテーション属性を String 型にする必要があり、型安全性が損なわれるため、これは望ましくありません。

そのため、Apache Geode の Spring Data は、Spring でよく使用される別のパターンである Configurers を借用しています。Spring/Web MVC では、org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer (Javadoc) を含む、さまざまな Configurer インターフェースが提供されています。

Configurers デザインパターンは、アプリケーション開発者が起動時にコンポーネントまたは Bean の構成をカスタマイズするためのコールバックを受け取ることを可能にします。フレームワークは、ユーザーが提供したコードをコールバックして、実行時に構成を調整します。このパターンの一般的な用途の一つは、アプリケーションの実行環境に基づいて条件付き構成を提供することです。

Apache Geode 用の Spring Data は、アノテーションによって作成される Spring マネージド Bean が初期化される前に、実行時にアノテーションベースの構成メタデータのさまざまな側面をカスタマイズするための Configurer コールバックインターフェースをいくつか提供します。

  • 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 定義では、プロパティプレースホルダー、ファクトリメソッドパラメーターでの @Value アノテーションを使用した SpEL 式など、他の Spring コンテナー機能を利用できます。

Spring Data によって Apache Geode に提供されるすべての Configurers は、コールバックで 2 ビットの情報を受け取ります。アノテーションによって Spring コンテナーに作成された Bean の名前と、アノテーションによって Apache Geode コンポーネントの作成と構成に使用される FactoryBean への参照です (たとえば、ClientCache インスタンスは ClientCacheFactoryBean を使用して作成および構成されます)。

SDG FactoryBeans は SDG パブリック API の一部であり、この新しいアノテーションベースの設定モデルが提供されていない場合、Spring の Java ベースのコンテナー構成で使用することになります。実際、アノテーション自体も設定に同じ FactoryBeans を使用しています。つまり、本質的には、アノテーションは利便性のために追加の抽象化レイヤーを提供するファサードなのです。

Configurer は他の POJO と同様に通常の Bean 定義として宣言できるため、プロパティプレースホルダーと SpEL 式の両方を使用する Conditions と Spring プロファイルの使用など、さまざまな Spring 構成オプションを組み合わせることができます。これらの便利な機能やその他の機能により、より高度で柔軟な構成を作成できます。

ただし、Configurers が唯一の選択肢ではありません。

6.6. Properties を使用したランタイム構成

Configurers に加えて、アノテーションベースの構成モデル内の各アノテーション属性は、対応する構成プロパティ(プレフィックスは spring.data.gemfire.)に関連付けられており、Spring Boot application.properties ファイルで宣言できます。

前の例を基に、クライアントの application.properties ファイルは次のプロパティセットを定義します。

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

対応するサーバーの application.properties ファイルでは、次のプロパティが定義されます。

サーバー application.properties
spring.data.gemfire.cache.log-level=info
spring.data.gemfire.cache.server.port=40404
spring.data.gemfire.cache.server.Venus.port=43434
spring.data.gemfire.cache.server.Saturn.port=41414
spring.data.gemfire.cache.server.Neptune.port=41414

次に、@ClientCacheApplication クラスを次のように簡略化できます。

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

また、@CacheServerApplication クラスは次のようになります。

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

上の例は、アノテーションベースの Bean に「名前を付ける」ことがなぜ重要なのかを示しています(特定のケースで必須という理由以外にも)。名前を付けることで、Spring コンテナー内の Bean を XML、プロパティ、Java から参照できるようになります。次の例に示すように、アノテーションで定義された Bean を、どのような目的でもアプリケーションクラスに挿入することも可能です。

@Component
class MyApplicationComponent {

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

  ...
}

同様に、アノテーション定義の Bean に名前を付けると、beanName がコールバックに渡される 2 つの引数のうちの 1 つであるため、Configurer をコーディングして特定の「名前付き」Bean をカスタマイズできます。

多くの場合、関連付けられたアノテーション属性プロパティには、「名前付き」プロパティと「名前なし」プロパティの 2 つの形式があります。

次の例はそのような配置を示しています。

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

上記には名前付き CacheServers が 3 つありますが、名前のない CacheServer プロパティも 1 つあります。このプロパティは、そのプロパティの未指定値(名前付き CacheServers を含む)のデフォルト値を提供します。つまり、「金星」は自身の bind-address を設定して上書きしますが、「土星」と「海王星」は「名前のない」 spring.data.gemfire.cache.server.bind-address プロパティを継承します。

どのアノテーション属性がプロパティベースの構成をサポートしているか、また、デフォルトの「名前のない」プロパティではなく「名前付き」プロパティをサポートしているかどうかについては、アノテーションの Javadoc を参照してください。

6.6.1. Properties の Properties 

通常の Spring 形式では、Properties を他の Properties の観点から表現することもできます。次の例は、application.properties ファイルで設定されるネストされたプロパティを示しています。

プロパティのプロパティ
spring.data.gemfire.cache.server.port=${gemfire.cache.server.port:40404}

次の例は、Java で設定されるネストされたプロパティを示しています。

プロパティプレースホルダーネスト
@Bean
CacheServerConfigurer cacheServerPortConfigurer(
    @Value("${gemfire.cache.server.port:${some.other.property:40404}}")
    int cacheServerPort) {
  ...
}
プロパティプレースホルダーのネストには任意の深さを設定できます。

6.7. 組み込みサービスの設定

Apache Geode は、ユースケースに応じて、アプリケーションに必要なさまざまな組み込みサービスを開始する機能を提供します。

6.7.1. 埋め込みロケーターの設定

前述の通り、Apache Geode ロケータはクライアントがクラスター内のサーバーに接続し、サーバーを見つけるために使用されます。また、既存のクラスターに参加する新しいメンバーも、ロケータを使用してピアを見つけます。

Apache Geode アプリケーションを開発するアプリケーション開発者にとって、Spring Boot および Spring Data を 2 ~ 3 台の Apache Geode サーバーで構成する小規模なクラスターを起動しておくと便利な場合があります。個別の Locator プロセスを起動する代わりに、次のように Spring Boot の @CacheServerApplication クラスに @EnableLocator アノテーションを付与することができます。

組み込みロケーターを実行する Spring、Apache Geode、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、-enabled アプリケーションを起動できます。

ロケータに接続する Spring、Apache Geode、CacheServer アプリケーション
@SpringBootApplication
@CacheServerApplication(locators = "localhost[10334]")
class ServerApplication { .. }

次のように、前に示した両方のアプリケーションクラスを 1 つのクラスに結合し、IDE を使用して異なる実行プロファイル構成を作成し、Java システムプロパティを使用してわずかに変更された構成で同じクラスの異なるインスタンスを起動することもできます。

Spring CacheServer アプリケーションは組み込みのロケーターを実行し、ロケーターに接続します
@SpringBootApplication
@CacheServerApplication(locators = "localhost[10334]")
public class ServerApplication {

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

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

}

次に、実行プロファイルごとに、次のシステムプロパティを設定および変更できます。

IDE 実行プロファイルの構成
spring.data.gemfire.name=SpringCacheServerOne
spring.data.gemfire.cache.server.port=41414
spring.profiles.active=embedded-locator

ServerApplication クラスの実行プロファイルのうち 1 つだけ、Java システムプロパティ -Dspring.profiles.active=embedded-locator を設定します。その後、他の実行プロファイルごとに ..name と ..cache.server.port を変更し、ローカルシステム上で Apache Geode サーバーの小規模なクラスター(分散システム)を実行します。

@EnableLocator アノテーションは開発時のみの使用を想定しており、アプリケーション開発者が本番環境で使用するものではありません。ロケーターはクラスター内でスタンドアロンの独立したプロセスとして実行することを強くお勧めします。

Apache Geode ロケーターの仕組みに関する詳細は、こちら [Apache] (英語) を参照してください。

6.7.2. 組み込みマネージャーの設定

Apache Geode マネージャーは、クラスタ内の別のピアメンバーまたはノードであり、クラスタの「管理」を担います。管理には、Regions、Indexes、DiskStores の作成などに加え、クラスタコンポーネントの実行時操作と動作の監視が含まれます。

Manager は、JMX 対応クライアント(Gfsh シェルツールなど)が Manager に接続してクラスタを管理できるようにします。また、JConsole や JVisualVM などの JDK 提供ツールも JMX 対応クライアントであれば、Manager に接続することも可能です。

先ほど示した Spring、@CacheServerApplication もマネージャーとして有効化したい場合もあるでしょう。そのためには、Spring、@Configuration、@SpringBootApplication クラスに @EnableManager アノテーションを追加してください。

デフォルトでは、Manager は localhost にバインドし、1099 のデフォルトの Manager ポートをリッスンします。Manager のいくつかの機能は、アノテーション属性または対応するプロパティを使用して設定できます。

次の例は、Java で埋め込みマネージャーを作成する方法を示しています。

組み込みマネージャーを実行する Spring CacheServer アプリケーション
@SpringBootApplication
@CacheServerApplication(locators = "localhost[10334]")
public class ServerApplication {

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

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

}

上記のクラスを使用すると、次のように Gfsh を使用して小規模なクラスターに接続し、管理することもできます。

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

Monitor and Manage {data-store-name}

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

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

組み込みの Locator も有効になっているため、Locator を介して間接的に Manager に接続できます。Locator は、JMX クライアントがクラスタ内の Manager に接続して見つけることを可能にします。Manager が存在しない場合は、Locator が Manager のロールを引き継ぎます。ただし、Locator が存在しない場合は、以下のコマンドを使用して Manager に直接接続する必要があります。

Gfsh connect コマンドはマネージャーに直接接続します
gfsh>connect --jmx-manager=localhost[1099]
@EnableLocator アノテーションと同様に、@EnableManager アノテーションも開発時のみの使用を想定しており、アプリケーション開発者が本番環境で使用するものではありません。マネージャーは、ロケーターと同様に、クラスター内でスタンドアロンかつ独立した専用プロセスとして動作することを強くお勧めします。

Apache Geode の管理と監視に関する詳細は、こちら [Apache] (英語) を参照してください。

6.7.3. 組み込み HTTP サーバーの設定

Apache Geode は組み込み HTTP サーバーも実行できます。現在の実装は Eclipse Jetty (英語) によってサポートされています。

組み込み HTTP サーバーは、Apache Geode の管理 (管理者) REST API (公開 API ではありません)、開発者向け REST API [Apache] (英語) 、脈拍モニタリング Web アプリケーション [Apache] (英語) をホストするために使用されます。

ただし、これらの Apache Geode 提供の Web アプリケーションを使用するには、システムに Apache Geode の完全インストールがインストールされ、GEODE_HOME 環境変数がインストールディレクトリに設定されている必要があります。

埋め込み HTTP サーバーを有効にするには、次のように、@PeerCacheApplication または @CacheServerApplication アノテーションが付けられたクラスに @EnableHttpService アノテーションを追加します。

組み込み HTTP サーバーを実行する Spring CacheServer アプリケーション
@SpringBootApplication
@CacheServerApplication
@EnableHttpService
public class ServerApplication { .. }

デフォルトでは、組み込み HTTP サーバーはポート 7070 で HTTP クライアントリクエストをリッスンします。もちろん、必要に応じてアノテーション属性または対応する構成プロパティを使用してポートを調整することもできます。

HTTP サポートと提供されるサービスの詳細については、前のリンクを参照してください。

6.7.4. 組み込み Memcached サーバーの設定 (ジェムキャッシュ)

Apache Geode は Memcached プロトコルも実装しており、Memcached クライアントへのサービス提供も可能です。つまり、Memcached クライアントは Apache Geode クラスタに接続し、クラスタ内の Apache Geode サーバーが実際の Memcached サーバーであるかのように Memcached 操作を実行できます。

埋め込み Memcached サービスを有効にするには、次のように、@PeerCacheApplication または @CacheServerApplication アノテーションが付けられたクラスに @EnableMemcachedServer アノテーションを追加します。

組み込み Memcached サーバーを実行する Spring CacheServer アプリケーション
@SpringBootApplication
@CacheServerApplication
@EnabledMemcachedServer
public class ServerApplication { .. }

Apache Geode の Memcached サービス( "Gemcached" と呼ばれています)の詳細については、こちら [Apache] (英語) を参照してください。

6.7.5. 組み込み Redis サーバーの構成

Apache Geode は Redis サーバープロトコルも実装しており、これにより Redis クライアントは Apache Geode サーバーのクラスターに接続して通信し、Redis コマンドを発行できるようになります。本稿執筆時点では、Apache Geode における Redis サーバープロトコルのサポートはまだ実験段階です。

埋め込み Redis サービスを有効にするには、次のように、@PeerCacheApplication または @CacheServerApplication アノテーションが付けられたクラスに @EnableRedisServer アノテーションを追加します。

組み込み Redis サーバーを実行する Spring CacheServer アプリケーション
@SpringBootApplication
@CacheServerApplication
@EnableRedisServer
public class ServerApplication { .. }
Spring [Boot] アプリケーションクラスパスで org.apache.geode:geode-redis モジュールを明示的に宣言する必要があります。

Apache Geode の Redis アダプターに関する詳細はこちら [Apache] (英語) を参照してください。

6.8. ロギングの構成

多くの場合、Apache Geode が何をいつ実行しているかを正確に把握するために、ログ記録をオンにする必要があります。

ロギングを有効にするには、次のように、アプリケーションクラスに @EnableLogging アノテーションを付け、適切な属性または関連プロパティを設定します。

ログ記録が有効になっている Spring ClientCache アプリケーション
@SpringBootApplication
@ClientCacheApplication
@EnableLogging(logLevel="info", logFile="/absolute/file/system/path/to/application.log)
public class ClientApplication { .. }

logLevel 属性はすべてのキャッシュベースのアプリケーションアノテーション (たとえば、@ClientCacheApplication(logLevel="info")) で指定できますが、@EnableLogging アノテーションを使用すると、ログ記録の動作をカスタマイズする方が簡単です。

さらに、application.properties の spring.data.gemfire.logging.level プロパティを設定することで、log-level を構成することもできます。

詳細については、@EnableLogging アノテーション Javadoc を参照してください。

6.9. 統計情報の設定

Apache Geode の実行時におけるより詳細な分析を行うには、統計情報を有効にします。統計データを収集することで、複雑な問題(多くの場合、分散して発生し、タイミングが重要な要素となる)が発生した場合のシステム分析とトラブルシューティングが容易になります。

統計が有効になっている場合は、Apache Geode の VSD (視覚統計表示) [Apache] (英語) ツールを使用して、収集された統計データを分析できます。

統計を有効にするには、次のように、アプリケーションクラスに @EnableStatistics アノテーションを付けます。

統計が有効になっている Spring ClientCache アプリケーション
@SpringBootApplication
@ClientCacheApplication
@EnableStatistics
public class ClientApplication { .. }

サーバーで統計情報を有効にすることは、パフォーマンスを評価する際に特に役立ちます。そのためには、@PeerCacheApplication または @CacheServerApplication クラスに @EnableStatistics アノテーションを付けます。

@EnableStatistics アノテーション属性または関連プロパティを使用して、統計の収集および収集プロセスをカスタマイズできます。

詳細については、@EnableStatistics アノテーション Javadoc を参照してください。

Apache Geode の統計に関する詳細は、こちら [Apache] (英語) を参照してください。

6.10. PDX の設定

Apache Geode の強力な機能の一つは PDX 直列化 [Apache] (英語) です。PDX の詳細な説明はこのドキュメントの範囲外ですが、PDX を使用した直列化は Java 直列化よりもはるかに優れた代替手段であり、次のような利点があります。

  • PDX は集中型の型レジストリを使用して、オブジェクトの直列化されたバイトをよりコンパクトに保ちます。

  • PDX は中立的な直列化形式であり、Java クライアントとネイティブクライアントの両方が同じデータセットで操作できます。

  • PDX はバージョン管理をサポートしており、変更された PDX 直列化オブジェクトの古いバージョンまたは新しいバージョンを使用している既存のアプリケーションに影響を与えることなく、データ損失なしでオブジェクトフィールドを追加または削除できます。

  • PDX を使用すると、オブジェクトを最初にデ直列化する必要なく、OQL クエリ射影と述語でオブジェクトフィールドに個別にアクセスできます。

一般に、Apache Geode での直列化は、通常の分散およびレプリケーションプロセス中にデータがクライアントとサーバー間で転送されるときや、クラスター内のピア間で転送されるとき、またデータがオーバーフローしたときやディスクに永続化されるときに必要になります。

PDX 直列化を有効にすることは、すべてのアプリケーションドメインオブジェクト型を変更して java.io.Serializable を実装するよりもはるかに簡単です。特に、アプリケーションドメインモデルにそのような制限を課すことが望ましくない場合や、直列化するオブジェクトを制御できない場合は、サードパーティライブラリを使用する場合に特に当てはまります (たとえば、Coordinate 型の地理空間 API を考えてみましょう)。

PDX を有効にするには、次のようにアプリケーションクラスに @EnablePdx アノテーションを付けます。

PDX が有効になっている Spring ClientCache アプリケーション
@SpringBootApplication
@ClientCacheApplication
@EnablePdx
public class ClientApplication { .. }

通常、アプリケーションのドメインオブジェクト型は、org.apache.geode.pdx.PdxSerializable (英語) インターフェースを実装するか、直列化する必要があるすべてのアプリケーションドメインオブジェクト型を処理するために、org.apache.geode.pdx.PdxSerializer (英語) インターフェースの非侵入的な実装を実装して登録することができます。

残念ながら、Apache Geode では PdxSerializer を 1 つしか登録できないため、すべてのアプリケーションドメインオブジェクト型を単一の PdxSerializer インスタンスで処理する必要があることになります。しかし、これは深刻なアンチパターンであり、メンテナンス不可能なメソッドです。

Apache Geode に登録できる PdxSerializer インスタンスは 1 つだけですが、アプリケーションドメインオブジェクト型ごとに 1 つの PdxSerializer 実装を作成するのが合理的です。

複合ソフトウェア設計パターン [Wikipedia] (英語) を使用すると、アプリケーションドメインオブジェクト型固有の PdxSerializer インスタンスをすべて集約し、単一の PdxSerializer インスタンスとして機能する PdxSerializer インターフェースの実装を提供して登録できます。

この複合 PdxSerializer を Spring コンテナー内の管理対象 Bean として宣言し、serializerBeanName 属性を使用して @EnablePdx アノテーション内の Bean 名でこの複合 PdxSerializer を参照できます。Apache Geode 用の Spring Data が、ユーザーに代わって Apache Geode への登録を行います。

次の例は、カスタム複合 PdxSerializer を作成する方法を示しています。

PDX が有効になっている Spring ClientCache アプリケーション (カスタム複合 PdxSerializer を使用)
@SpringBootApplication
@ClientCacheApplication
@EnablePdx(serializerBeanName = "compositePdxSerializer")
public class ClientApplication {

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

Apache Geode の org.apache.geode.pdx.ReflectionBasedAutoSerializer (英語) を Spring コンテキストで Bean 定義として宣言することもできます。

あるいは、Apache Geode のより堅牢な org.springframework.data.gemfire.mapping.MappingPdxSerializer (Javadoc) の代わりに Spring Data を使用する必要があります。これは、Spring Data マッピングメタデータとインフラストラクチャを直列化プロセスに適用して、リフレクションのみの場合よりも効率的な処理を実現します。

PDX の他の多くの側面と機能は、@EnablePdx アノテーション属性または関連する構成プロパティを使用して調整できます。

詳細については、@EnablePdx アノテーション Javadoc を参照してください。

6.11. Apache Geode プロパティの設定

gemfire.properties [Apache] (英語) の多くは、SDG アノテーションベースの構成モデルでアノテーションを使用して便利にカプセル化および抽象化されていますが、あまり使用されない Apache Geode プロパティは、引き続き @EnableGemFireProperties アノテーションからアクセスできます。

アプリケーションクラスに @EnableGemFireProperties アノテーションを付けると便利で、gemfire.properties ファイルを作成したり、アプリケーションの起動時にコマンドラインで Apache Geode プロパティを Java システムプロパティとして設定したりする代わりに使用できます。

アプリケーションを本番環境にデプロイする際は、これらの Apache Geode プロパティを gemfire.properties ファイルで設定することをお勧めします。ただし、開発段階では、プロトタイピング、デバッグ、テストの目的で、必要に応じてこれらのプロパティを個別に設定することが便利な場合があります。

通常は気にする必要がない、あまり一般的ではない Apache Geode プロパティの例としては、ack-wait-threshold、disable-tcp、socket-buffer-size などがあります。

Apache Geode プロパティを個別に設定するには、アプリケーションクラスに @EnableGemFireProperties アノテーションを付け、次のように、対応する属性を使用して、Apache Geode によって設定されたデフォルト値から変更する Apache Geode プロパティを設定します。

特定の Apache Geode プロパティが設定された Spring ClientCache アプリケーション
@SpringBootApplication
@ClientCacheApplication
@EnableGemFireProperties(conflateEvents = true, socketBufferSize = 16384)
public class ClientApplication { .. }

Apache Geode プロパティの一部はクライアント固有 (たとえば、conflateEvents) であり、その他はサーバー固有 (たとえば、distributedSystemId、enableNetworkPartitionDetection、enforceUniqueHost、memberTimeout、redundancyZone など) であることに注意してください。

Apache Geode の特性に関する詳細は、こちら [Apache] (英語) を参照してください。

6.12. 領域の構成

これまで、PDX 以外の Apache Geode の管理機能の設定を中心に議論してきました。具体的には、キャッシュインスタンスの作成、組み込みサービスの起動、ログ記録と統計情報の有効化、PDX の設定、gemfire.properties を使用した低レベルの設定と動作への影響などです。これらの設定オプションはどれも重要ですが、アプリケーションに直接関係するものではありません。つまり、アプリケーションデータを保存し、誰でもアクセスできるようにするための場所が必要なのです。

Apache Geode はキャッシュ内のデータを領域 [Apache] (英語) に整理します。リージョンはリレーショナルデータベースのテーブルのようなものだと考えてください。一般的に、リージョンには単一型のオブジェクトのみを格納するように設計されているため、効果的なインデックスの作成やクエリの記述が容易になります。インデックスについては後ほど説明します。

以前は、Apache Geode の Spring Data ユーザーは、API からの SDG の FactoryBeans を Spring の Java ベースのコンテナー構成とともに使用するか、XML を使用するかに関係なく、非常に詳細な Spring 構成メタデータを記述して、アプリケーションがデータを保存するために使用するリージョンを明示的に定義および宣言する必要がありました。

次の例は、Java でリージョン Bean を構成する方法を示しています。

Spring の Java ベースのコンテナー構成を使用したリージョン Bean の定義例
@Configuration
class GemFireConfiguration {

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

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

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

      return exampleRegion;
  }

  ...
}

次の例は、同じリージョン Bean を XML で構成する方法を示しています。

SDG の XML 名前空間を使用した領域 Bean の定義例
<gfe:partitioned-region id="exampleRegion" name="Example" persistent="true">
    ...
</gfe:partitioned-region>

Java と XML の設定はどちらもそれほど難しくありませんが、特にアプリケーションで多数のリージョンが必要な場合は、どちらも煩雑になる可能性があります。多くのリレーショナルデータベースベースのアプリケーションでは、数百、あるいは数千ものテーブルが存在することがあります。

これらすべての Region を手作業で定義・宣言するのは面倒で、エラーが発生しやすくなります。しかし、よりよい方法があります。

アプリケーションドメインオブジェクト(エンティティ)自体に基づいてリージョンを定義および構成できるようになりました。よりきめ細かな制御が必要な場合を除き、Spring 構成メタデータで Region または Bean の定義を明示的に定義する必要はなくなりました。

リージョンの作成を簡素化するために、Apache Geode 用の Spring Data は、Spring Data リポジトリの使用と、新しい @EnableEntityDefinedRegions アノテーションを使用したアノテーションベースの構成の表現力を組み合わせます。

ほとんどの Spring Data アプリケーション開発者は、Apache Geode のデータアクセス操作を最適化するように特別にカスタマイズされた Apache Geode の実装/拡張の Spring Data リポジトリの抽象化と Spring Data にすでに精通しているはずです。

まず、アプリケーション開発者は、次のようにアプリケーションのドメインオブジェクト (エンティティ) を定義することから始めます。

アプリケーションドメインオブジェクト型モデリングの本
@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 は、基本的なデータアクセス操作 (CRUD) に加え、シンプルなクエリ ( findById(..) など) をサポートするデータアクセスオブジェクト (DAO) です。リポジトリインターフェースでクエリメソッド ( List<BooK> findByAuthor(Author author); など) を宣言することで、より高度なクエリを追加定義できます。

内部的には、Spring Data for Apache Geode は、Spring コンテナーがブートストラップされる際に、アプリケーションのリポジトリインターフェースの実装を提供します。SDG は、規約に従っている限り、定義したクエリメソッドも実装します。

Book クラスを定義する際に、エンティティの型に Spring Data から Apache Geode へのマッピングアノテーション @Region を宣言することで、Book のインスタンスがマッピング(格納)されるリージョンも指定しました。もちろん、リポジトリインターフェース(この場合は BookRepository)の型パラメーターで参照されるエンティティ型(この場合は Book)に @Region のアノテーションが付いていない場合は、エンティティ型の単純なクラス名(この場合は Book)から名前が派生します。

Apache Geode の Spring Data は、アプリケーションで定義されているすべてのエンティティのマッピングメタデータを含むマッピングコンテキストを使用して、実行時に必要なすべてのリージョンを決定します。

この機能を有効にして使用するには、次のように、アプリケーションクラスに @EnableEntityDefinedRegions アノテーションを付けます。

エンティティ定義のリージョン構成
@SpringBootApplication
@ClientCacheApplication
@EnableEntityDefinedRegions(basePackages = "example.app.domain")
@EnableGemfireRepositories(basePackages = "example.app.repo")
class ClientApplication { .. }
エンティティクラスからリージョンを作成する方法は、アプリケーションで Spring Data リポジトリを使用する場合に最も便利です。Apache Geode のリポジトリサポートである Spring Data は、前述の例に示すように、@EnableGemfireRepositories アノテーションによって有効化されます。
現在、@Region で明示的にアノテーションされたエンティティクラスのみがスキャンによって検出され、リージョンが作成されます。エンティティクラスが @Region で明示的にマッピングされていない場合、リージョンは作成されません。

デフォルトでは、@EnableEntityDefinedRegions アノテーションは、@EnableEntityDefinedRegions アノテーションが宣言されている構成クラスのパッケージから開始して、エンティティクラスを再帰的にスキャンします。

ただし、アプリケーションエンティティクラスを含むパッケージ名を使用して basePackages 属性を設定することで、スキャン中の検索を制限するのが一般的です。

あるいは、より型安全な basePackageClasses 属性を使用してスキャンするパッケージを指定することもできます。そのためには、属性を、エンティティのクラスを含むパッケージ内のエンティティ型に設定するか、スキャンするパッケージを識別するために特別に作成された非エンティティプレースホルダークラスを使用します。

次の例は、スキャンするエンティティ型を指定する方法を示しています。

エンティティクラス型を使用したエンティティ定義のリージョン構成
@SpringBootApplication
@ClientCacheApplication
@EnableGemfireRepositories
@EnableEntityDefinedRegions(basePackageClasses = {
    example.app.books.domain.Book.class,
    example.app.customers.domain.Customer.class
})
class ClientApplication { .. }

Spring の @ComponentScan アノテーションのようにスキャンを開始する場所を指定することに加えて、org.springframework.context.annotation.ComponentScan.Filter アノテーションとまったく同じセマンティクスを持つ include および exclude フィルターを指定できます。

詳細については、@EnableEntityDefinedRegions アノテーション Javadoc を参照してください。

6.12.1. 型固有の領域の設定

Apache Geode は、さまざまな種類のリージョン [Apache] (英語) をサポートしています。各リージョン型は、リージョンの DataPolicy [Apache] (英語) に対応しており、リージョン内のデータがどのように管理されるか(分散、複製など)を正確に決定します。

その他の設定(リージョンの scope など)もデータの管理方法に影響を与える可能性があります。詳細については、Apache Geode ユーザーガイドの “保管および配送オプション” [Apache] (英語) を参照してください。

アプリケーションドメインオブジェクト型に汎用 @Region マッピングアノテーションを付与すると、Spring Data for Apache Geode が作成するリージョンの種類を決定します。SDG のデフォルトの戦略では、作成するリージョンの種類を決定する際にキャッシュの種類が考慮されます。

例: @ClientCacheApplication アノテーションを使用してアプリケーションを ClientCache として宣言した場合、SDG はデフォルトでクライアント側の PROXY (Region)を作成します。一方、@PeerCacheApplication または @CacheServerApplication アノテーションを使用してアプリケーションをピア側の Cache として宣言した場合、SDG はデフォルトでサーバー側の PARTITION (Region)を作成します。

もちろん、必要に応じていつでもデフォルトを上書きできます。Spring Data が Apache Geode に適用したデフォルトを上書きするために、4 つの新しいリージョンマッピングアノテーションが導入されました。

  • @ClientRegion

  • @LocalRegion

  • @PartitionRegion

  • @ReplicateRegion

@ClientRegion マッピングアノテーションはクライアントアプリケーションに固有のものです。上記の他のすべてのリージョンマッピングアノテーションは、ピア Cache が組み込まれたサーバーアプリケーションでのみ使用できます。

クライアントアプリケーションがローカル専用のリージョンを作成して使用する必要がある場合があります。これは、他のリージョンからデータを集約し、ローカルでデータを分析し、ユーザーに代わってアプリケーションが実行する機能を実行するためなどです。この場合、他のアプリケーションが結果にアクセスする必要がない限り、データをサーバーに再配布する必要はありません。このリージョンは一時的なものであり、使用後に破棄される場合もあります。これは、リージョン自体にアイドルタイムアウト (TTI) と Time-To-Live (TTL) の有効期限ポリシーを設定することで実現できます。(有効期限に関するポリシーの詳細については、"有効期限の設定" を参照してください。)

リージョンレベルのアイドルタイムアウト (TTI) および Time-To-Live (TTL) 有効期限ポリシーは、エントリレベルの TTI および TTL 有効期限ポリシーとは独立しており、異なります。

いずれの場合でも、データがサーバー上の同じ名前の対応するリージョンに配布されないローカル専用のクライアントリージョンを作成する場合は、次のように、@ClientRegion マッピングアノテーションを宣言し、shortcut 属性を ClientRegionShortcut.LOCAL に設定できます。

ローカルのみのクライアントリージョンを持つ Spring ClientCache アプリケーション
@ClientRegion(shortcut = ClientRegionShortcut.LOCAL)
class ClientLocalEntityType { .. }

すべてのリージョン型固有のアノテーションは、リージョン型間で共通であると同時に、その型のリージョンにのみ固有の追加属性を提供します。例: PartitionRegion アノテーションの collocatedWith 属性と redundantCopies 属性は、サーバー側の PARTITION リージョンにのみ適用されます。

Apache Geode リージョン型の詳細については、こちら [Apache] (英語) を参照してください。

6.12.2. 構成されたクラスター定義のリージョン

@EnableEntityDefinedRegions アノテーションに加えて、Apache Geode 用の Spring Data は、逆アノテーションである @EnableClusterDefinedRegions も提供します。アプリケーションのユースケース (UC) と要件に基づいて定義および駆動されるエンティティクラスに基づいてリージョンを定義するのではなく (最も一般的で論理的なアプローチ)、ClientCache アプリケーションが接続するクラスターですでに定義されているリージョンからリージョンを宣言することもできます。

これにより、サーバークラスターをデータ定義の主要ソースとして設定を一元管理し、クラスター内のすべてのクライアントアプリケーションの設定を一貫性のあるものにすることができます。これは、クラウド管理環境における負荷の増加に対応するために、同じクライアントアプリケーションのインスタンスを迅速にスケールアップする場合に特に役立ちます。

アイデアとしては、クライアントアプリケーションがデータディクショナリを操作するのではなく、ユーザーが Apache Geode の Gfsh CLI シェルツールを使用してリージョンを定義するというものがあります。これにより、クラスタにピアを追加しても、Apache Geode のクラスタ構成サービスによってその構成が記憶されるため、それらのピアも同じ構成を持ち、共有できるという利点があります。

たとえば、ユーザーは Gfsh で次のように Region を定義することができます。

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 の Cluster Configuration Service を使用すると、増加した負荷 (バックエンド) を処理するためにサーバーのクラスターに追加されたピアメンバーにも同じ構成が設定されます。例:

クラスターにピアメンバーを追加する
gfsh>list members
  Name    | Id
--------- | ----------------------------------------------
Locator   | 10.0.0.121(Locator:68173:locator)<ec><v0>:1024
ServerOne | 10.0.0.121(ServerOne:68242)<v3>:1025
ServerTwo | 10.0.0.121(ServerTwo:68372)<v4>:1026

gfsh>start server --name=ServerThree --log-level=config --server-port=41414
Starting a Geode Server in /Users/you/geode/cluster/ServerThree...
...
Server in /Users/you/geode/cluster/ServerThree... on 10.0.0.121[41414] as ServerThree is currently online.
Process ID: 68467
Uptime: 3 seconds
Geode Version: 1.2.1
Java Version: 1.8.0_152
Log File: /Users/you/geode/cluster/ServerThree/ServerThree.log
JVM Arguments: -Dgemfire.default.locators=10.0.0.121[10334]
  -Dgemfire.use-cluster-configuration=true
  -Dgemfire.start-dev-rest-api=false
  -Dgemfire.log-level=config
  -XX:OnOutOfMemoryError=kill -KILL %p
  -Dgemfire.launcher.registerSignalHandlers=true
  -Djava.awt.headless=true
  -Dsun.rmi.dgc.server.gcInterval=9223372036854775806
Class-Path: /Users/you/geode/cluster/apache-geode-1.2.1/lib/geode-core-1.2.1.jar
  :/Users/you/geode/cluster/apache-geode-1.2.1/lib/geode-dependencies.jar

gfsh>list members
   Name     | Id
----------- | ----------------------------------------------
Locator     | 10.0.0.121(Locator:68173:locator)<ec><v0>:1024
ServerOne   | 10.0.0.121(ServerOne:68242)<v3>:1025
ServerTwo   | 10.0.0.121(ServerTwo:68372)<v4>:1026
ServerThree | 10.0.0.121(ServerThree:68467)<v5>:1027

gfsh>describe member --name=ServerThree
Name        : ServerThree
Id          : 10.0.0.121(ServerThree:68467)<v5>:1027
Host        : 10.0.0.121
Regions     : Books
PID         : 68467
Groups      :
Used Heap   : 37M
Max Heap    : 3641M
Working Dir : /Users/you/geode/cluster/ServerThree
Log file    : /Users/you/geode/cluster/ServerThree/ServerThree.log
Locators    : 10.0.0.121[10334]

Cache Server Information
Server Bind              :
Server Port              : 41414
Running                  : true
Client Connections       : 0

ご覧のとおり、"ServerThree" に "Books" リージョンが追加されました。サーバーの一部またはすべてがダウンした場合でも、復旧時には "Books" リージョンと同じ構成が保持されます。

クライアント側では、Book Store オンラインサービスに対して書籍を処理するために、多数の Book Store クライアントアプリケーションインスタンスが起動される可能性があります。"Books" リージョンは、Book Store アプリケーションサービスを実装するために必要な多数のリージョンの 1 つである可能性があります。SDG では、各リージョンを個別に作成して設定する代わりに、次のようにクラスタからクライアントアプリケーションのリージョンを定義できます。

@EnableClusterDefinedRegions を使用してクラスターからクライアント領域を定義する
@ClientCacheApplication
@EnableClusterDefinedRegions
class BookStoreClientApplication {

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

    ...
}
@EnableClusterDefinedRegions はクライアント上でのみ使用できます。
clientRegionShortcut アノテーション属性を使用して、クライアント上に作成されるリージョンの種類を制御できます。デフォルトでは、クライアント PROXY リージョンが作成されます。「ニアキャッシュ」を実装するには、clientRegionShortcut を ClientRegionShortcut.CACHING_PROXY に設定します。この設定は、クラスタ定義のリージョンから作成されたすべてのクライアントリージョンに適用されます。クラスタ定義のリージョンから作成されたクライアントリージョンの個別の設定(データポリシーなど)を制御する場合は、リージョン名に基づくカスタムロジックを使用して RegionConfigurer (Javadoc) を実装できます。

これで、アプリケーションで "Books" リージョンを使用するのが簡単になります。"Books" リージョンは、次のように直接挿入できます。

「書籍」領域の使用
@org.springframework.stereotype.Repository
class BooksDataAccessObject {

    @Resource(name = "Books")
    private Region<ISBN, Book> books;

    // implement CRUD and queries with the "Books" Region
}

または、次のように、"Books" リージョンにマップされたアプリケーションドメイン型 (エンティティ) Book に基づいて、Spring Data リポジトリ定義を定義することもできます。

SD リポジトリで "Books" リージョンを使用する
interface BookRepository extends CrudRepository<Book, ISBN> {
    ...
}

その後、カスタム BooksDataAccessObject または BookRepository をアプリケーションサービスコンポーネントに挿入して、必要なビジネス機能を実行できます。

6.12.3. 追い出しの設定

Apache Geode でのデータ管理は、能動的な作業です。一般的にチューニングが必要であり、Apache Geode でメモリ内のデータを効果的に管理するには、複数の機能(たとえば、削除と有効期限の両方)を組み合わせる必要があります。

Apache Geode はインメモリデータグリッド(IMDG)であるため、データはメモリ内で管理され、クラスターに参加している他のノードに分散されます。これにより、レイテンシを最小限に抑え、スループットを最大化し、データの高可用性を確保します。アプリケーションのデータはすべてメモリに収まることは通常ありません(クラスター全体のノードであっても、ましてや単一のノードではなおさらです)。そのため、クラスターに新しいノードを追加することで容量を増やすことができます。これは一般的にリニアスケールアウトと呼ばれます(スケールアップとは対照的です。スケールアップとは、メモリ、CPU、ディスク、ネットワーク帯域幅など、基本的に負荷を処理するためにあらゆるシステムリソースを増やすことを意味します)。

それでも、ノードをクラスタ化している場合でも、通常は最も重要なデータのみをメモリに保持することが不可欠です。メモリ不足、あるいは限界に近い状態になることは、ほとんどの場合、良いことではありません。ストップザ・ワールド GC、あるいはさらに深刻な OutOfMemoryErrors(メモリ不足)は、アプリケーションを完全に停止させてしまいます。

そのため、メモリ管理を容易にし、最も重要なデータを保持するために、Apache Geode は Least Recently Used(LRU)エビクションをサポートしています。つまり、Apache Geode は Least Recently Used アルゴリズムを用いて、リージョンエントリが最後にアクセスされた日時に基づいてエントリを削除します。

削除を有効にするには、次のように、アプリケーションクラスに @EnableEviction アノテーションを付けます。

追い出しが有効になっている Spring アプリケーション
@SpringBootApplication
@PeerCacheApplication
@EnableEviction(policies = {
    @EvictionPolicy(regionNames = "Books", action = EvictionActionType.INVALIDATE),
    @EvictionPolicy(regionNames = { "Customers", "Orders" }, maximum = 90,
        action = EvictionActionType.OVERFLOW_TO_DISK,
        type = EvictonPolicyType.HEAP_PERCENTAGE)
})
class ServerApplication { .. }

削除ポリシーは通常、サーバーのリージョンに設定されます。

前述のように、policies 属性では、1 つ以上のネストされた @EvictionPolicy アノテーションを指定できます。各アノテーションは、エビクションポリシーを適用する必要のある 1 つ以上のリージョンに個別に対応します。

さらに、Apache Geode の org.apache.geode.cache.util.ObjectSizer (英語) インターフェースのカスタム実装を参照できます。これは、Spring コンテナーで Bean として定義でき、objectSizerName 属性を使用して名前で参照できます。

ObjectSizer を使用すると、リージョンに保存されるオブジェクトのサイズを評価および決定するために使用される条件を定義できます。

削除構成オプションの完全なリストについては、@EnableEviction アノテーション Javadoc を参照してください。

Apache Geode の追い出しに関する詳細は、こちら [Apache] (英語) を参照してください。

6.12.4. 有効期限の設定

削除機能に加えて、有効期限設定もメモリ管理に利用できます。これは、リージョンに格納されたエントリの有効期限を設定することで実現できます。Apache Geode は、有効期限ポリシーとして、Time-to-Live(TTL)と Idle-Timeout(TTI)の両方をサポートしています。

Apache Geode の Spring Data のアノテーションベースの有効期限設定は、Apache Geode バージョン 1.5 の Spring Data で追加された、以前の既存のエントリ有効期限アノテーションサポートに基づいています。

基本的に、Apache Geode の有効期限アノテーションサポートのための Spring Data は、Apache Geode の org.apache.geode.cache.CustomExpiry (英語) インターフェースのカスタム実装に基づいています。この o.a.g.cache.CustomExpiry 実装は、リージョンに格納されているユーザーのアプリケーションドメインオブジェクトをインスペクションし、型レベルの有効期限アノテーションの有無を確認します。

Apache Geode 用の Spring Data は、次の有効期限アノテーションを提供します。

  • Expiration

  • IdleTimeoutExpiration

  • TimeToLiveExpiration

アプリケーションドメインオブジェクト型には、次のように 1 つ以上の有効期限アノテーションを付けることができます。

アプリケーションドメインオブジェクト固有の有効期限ポリシー
@Region("Books")
@TimeToLiveExpiration(timeout = 30000, action = "INVALIDATE")
class Book { .. }

有効期限を有効にするには、次のように、アプリケーションクラスに @EnableExpiration アノテーションを付けます。

有効期限が有効になっている Spring アプリケーション
@SpringBootApplication
@PeerCacheApplication
@EnableExpiration
class ServerApplication { .. }

アプリケーションドメインオブジェクト型 レベルの有効期限ポリシーに加えて、次のように @EnableExpiration アノテーションを使用して、リージョンごとに有効期限ポリシーを直接個別に構成できます。

領域固有の有効期限ポリシーを備えた Spring アプリケーション
@SpringBootApplication
@PeerCacheApplication
@EnableExpiration(policies = {
    @ExpirationPolicy(regionNames = "Books", types = ExpirationType.TIME_TO_LIVE),
    @ExpirationPolicy(regionNames = { "Customers", "Orders" }, timeout = 30000,
        action = ExpirationActionType.LOCAL_DESTROY)
})
class ServerApplication { .. }

上記の例では、Books、Customers、Orders リージョンの有効期限ポリシーを設定しています。

有効期限ポリシーは通常、サーバーのリージョンに設定されます。

有効期限の設定オプションの完全なリストについては、@EnableExpiration アノテーション Javadoc を参照してください。

Apache Geode の有効期限に関する詳細は、こちら [Apache] (英語) を参照してください。

6.12.5. 圧縮の設定

削除や有効期限切れに加えて、メモリ消費量を削減するために、データ領域を圧縮するように構成することもできます。

Apache Geode では、プラグ可能な Compressors [Apache] (英語) または他の圧縮コーデックを使用して、メモリ内のリージョン値を圧縮できます。Apache Geode では、デフォルトで Google のスナッピー (英語) 圧縮ライブラリが使用されます。

圧縮を有効にするには、次のようにアプリケーションクラスに @EnableCompression アノテーションを付けます。

リージョン圧縮を有効にした Spring アプリケーション
@SpringBootApplication
@ClientCacheApplication
@EnableCompression(compressorBeanName = "MyCompressor", regionNames = { "Customers", "Orders" })
class ClientApplication { .. }
compressorBeanName 属性も regionNames 属性も必須ではありません。

compressorBeanName はデフォルトで SnappyCompressor に設定され、Apache Geode の SnappyCompressor [Apache] (英語) が有効になります。

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] (英語) を使用する)を使用する場合にのみ必要です。もちろん、他の圧縮ライブラリを使用する場合は、その圧縮ライブラリへの依存関係をアプリケーションのクラスパスに含める必要があります。さらに、選択した圧縮ライブラリを適応させるために Apache Geode の Compressor [Apache] (英語) インターフェースを実装し、Spring コンプレッサで Bean として定義し、compressorBeanName をこのカスタム Bean 定義に設定する必要があります。

詳細については、@EnableCompression アノテーション Javadoc を参照してください。

Apache Geode 圧縮に関する詳細はこちら (英語) を参照してください。

6.12.6. オフヒープメモリの設定

JVM のヒープメモリへの負荷を軽減し、GC アクティビティを最小限に抑えるもう 1 つの効果的な手段は、Apache Geode のオフヒープメモリサポートを使用することです。

リージョンエントリは JVM ヒープではなく、システムのメインメモリに保存されます。オフヒープメモリは、保存されるオブジェクトのサイズが均一で、ほとんどが 128KB 未満で、頻繁にデシリアライズする必要がない場合に最も効果的です(Apache Geode ユーザーガイド [Apache] (英語) を参照)。

オフヒープを有効にするには、次のようにアプリケーションクラスに @EnableOffHeap アノテーションを付けます。

オフヒープ対応の Spring アプリケーション
@SpringBootApplication
@PeerCacheApplication
@EnableOffHeap(memorySize = 8192m regionNames = { "Customers", "Orders" })
class ServerApplication { .. }

memorySize 属性は必須です。memorySize 属性の値は、リージョンが使用できるメインメモリの量をメガバイト(m)またはギガバイト(g)で指定します。

regionNames 属性は、メインメモリにエントリを格納する領域を指定する領域名の配列です。regionNames 属性が明示的に設定されていない場合、デフォルトではすべての領域がメインメモリを使用します。

あるいは、application.properties ファイルの spring.data.gemfire.cache.off-heap.memory-size および spring.data.gemfire.cache.off-heap.region-names プロパティを使用して、これらの @EnableOffHeap アノテーション属性の値を設定および構成することもできます。

詳細については、@EnableOffHeap アノテーション Javadoc を参照してください。

6.12.7. ディスクストアの構成

あるいは、リージョンがデータをディスクに永続化するように設定することもできます。また、リージョンエントリが削除された際に、データをディスクにオーバーフローするように設定することもできます。どちらの場合も、データの永続化およびオーバーフローには DiskStore が必要です。永続化またはオーバーフローが設定されたリージョンに明示的な DiskStore が設定されていない場合、Apache Geode は DEFAULT (DiskStore)を使用します。

データをディスクに永続化したりオーバーフローしたりする場合は、リージョン固有の DiskStores を定義することをお勧めします。

Apache Geode 用の Spring Data は、アプリケーションクラスに @EnableDiskStore および @EnableDiskStores アノテーションを付けることで、アプリケーション領域 DiskStores を定義および作成するためのアノテーションサポートを提供します。

@EnableDiskStores は、1 つ以上の @EnableDiskStore アノテーションを集約するための複合アノテーションです。

たとえば、Book 情報は主に外部データソース (Amazon など) からの参照データで構成される可能性がありますが、Order データはトランザクションの性質を持つ可能性が高く、アプリケーションが保持する必要があるもの (トランザクション量が十分に多い場合はディスクにオーバーフローする必要がある場合もあります) になります。少なくとも、書籍のパブリッシャーや作成者はそう願っています。

@EnableDiskStore アノテーションを使用すると、次のように DiskStore を定義および作成できます。

DiskStore を定義する Spring アプリケーション
@SpringBootApplication
@PeerCacheApplication
@EnableDiskStore(name = "OrdersDiskStore", autoCompact = true, compactionThreshold = 70,
    maxOplogSize = 512, diskDirectories = @DiskDiretory(location = "/absolute/path/to/order/disk/files"))
class ServerApplication { .. }

同様に、複合 @EnableDiskStores アノテーションを使用して、複数の DiskStore を定義できます。

Apache Geode のアノテーションベースの構成モデルの Spring Data の他のアノテーションと同様に、@EnableDiskStore と @EnableDiskStores には、実行時に作成される DiskStores をカスタマイズするための多くの属性と関連する構成プロパティがあります。

さらに、@EnableDiskStores アノテーションは、@EnableDiskStores アノテーション自体と組み合わせた @EnableDiskStore アノテーションから作成されたすべての DiskStores に適用される、共通の DiskStore 属性を定義します。個々の DiskStore 設定は特定のグローバル設定をオーバーライドしますが、@EnableDiskStores アノテーションは、アノテーションによって集約されたすべての DiskStores に適用される共通の設定属性を便利に定義します。

Apache Geode 用の Spring Data は、DiskStoreConfigurer コールバックインターフェースも提供します。これは、Java 構成で宣言でき、次の例に示すように、実行時に DiskStore をカスタマイズするために構成プロパティの代わりに使用できます。

カスタム DiskStore 構成を備えた Spring アプリケーション
@SpringBootApplication
@PeerCacheApplication
@EnableDiskStore(name = "OrdersDiskStore", autoCompact = true, compactionThreshold = 70,
    maxOplogSize = 512, diskDirectories = @DiskDiretory(location = "/absolute/path/to/order/disk/files"))
class ServerApplication {

  @Bean
  DiskStoreConfigurer ordersDiskStoreDiretoryConfigurer(
          @Value("${orders.disk.store.location}") String location) {

      return (beanName, diskStoreFactoryBean) -> {

          if ("OrdersDiskStore".equals(beanName) {
              diskStoreFactoryBean.setDiskDirs(Collections.singletonList(new DiskDir(location));
          }
      }
  }
}

使用可能な属性と関連する構成プロパティの詳細については、@EnableDiskStore (Javadoc) および @EnableDiskStores (Javadoc) アノテーションの Javadoc を参照してください。

Apache Geode リージョンの永続性とオーバーフロー(DiskStores を使用)に関する詳細は、こちら [Apache] (英語) を参照してください。

6.12.8. インデックスの設定

データにアクセスできない限り、リージョンにデータを保存してもあまり意味がありません。

Region.get(key) 操作に加えて、特にキーが事前にわかっている場合は、データを含むリージョンに対してクエリを実行することでデータを取得するのが一般的です。Apache Geode では、クエリはオブジェクトクエリ言語(OQL)を使用して記述され、クライアントがアクセスしたい特定のデータセットはクエリの述語(例: SELECT * FROM /Books b WHERE b.author.name = 'Jon Doe')で表現されます。

一般的に、インデックスなしでのクエリは非効率的です。インデックスなしでクエリを実行する場合、Apache Geode はフルテーブルスキャンと同等のクエリを実行します。

クエリ述語で使用されるオブジェクトのフィールドに対してインデックスが作成および維持され、クエリの射影によって表現される対象データと照合されます。キーインデックス [Apache] (英語) やハッシュ [Apache] (英語) インデックスなど、さまざまな種類のインデックスを作成できます。

Apache Geode 用の Spring Data を使用すると、データが保存およびアクセスされるリージョンにインデックスを簡単に作成できます。従来のように Spring 構成を使用して Index Bean 定義を明示的に宣言する代わりに、次のように Java で Index Bean 定義を作成できます。

Java config を使用したインデックス Bean 定義
@Bean("BooksIsbnIndex")
IndexFactoryBean bookIsbnIndex(GemFireCache gemfireCache) {

    IndexFactoryBean bookIsbnIndex = new IndexFactoryBean();

    bookIsbnIndex.setCache(gemfireCache);
    bookIsbnIndex.setName("BookIsbnIndex");
    bookIsbnIndex.setExpression("isbn");
    bookIsbnIndex.setFrom("/Books"));
    bookIsbnIndex.setType(IndexType.KEY);

    return bookIsbnIndex;
}

あるいは、次のように、XML を使用して Index Bean 定義を作成することもできます。

XML を使用したインデックス Bean の定義
<gfe:index id="BooksIsbnIndex" expression="isbn" from="/Books" type="KEY"/>

しかし、クエリ述語で使用されることが分かっているアプリケーションドメインオブジェクト型のフィールドにインデックスを直接定義することで、クエリを高速化できるようになりました。アプリケーションのリポジトリインターフェース上のユーザー定義クエリメソッドから生成された OQL クエリにもインデックスを適用できます。

先ほどの Book エンティティクラスの例を再利用して、次のように、BookRepository インターフェースのクエリメソッドで定義したクエリで使用されることがわかっている Book のフィールドにアノテーションを付けることができます。

インデックスを使用して書籍をモデリングするアプリケーションドメインオブジェクト型
@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 クラス定義では、author フィールドに @Indexed を、title フィールドに @LuceneIndexed をアノテーションしました。また、isbn フィールドには、以前は Spring Data の @Id アノテーションが付与されていました。このアノテーションは、Book インスタンスの一意の識別子を含むフィールドを識別します。また、Apache Geode の Spring Data では、@Id アノテーションが付与されたフィールドまたはプロパティが、エントリを格納する際にリージョンのキーとして使用されます。

  • @Id アノテーション付きフィールドまたはプロパティにより、Apache Geode KEY インデックスが作成されます。

  • @Indexed アノテーション付きフィールドまたはプロパティにより、Apache Geode HASH インデックス (デフォルト) が作成されます。

  • @LuceneIndexed アノテーション付きフィールドまたはプロパティにより、Apache Geode Lucene インデックスが作成され、Apache Geode の Lucene 統合とサポートによるテキストベースの検索で使用されます。

@Indexed アノテーションを属性設定なしで使用する場合、インデックス name、expression、fromClause は @Indexed アノテーションが追加されたクラスのフィールドまたはプロパティから導出されます。expression は、そのフィールドまたはプロパティの名前と全く同じです。fromClause は、ドメインオブジェクトのクラスの @Region アノテーションから導出されます。@Region アノテーションが指定されていない場合は、ドメインオブジェクトクラスの単純名が導出されます。

もちろん、@Indexed アノテーション属性のいずれかを明示的に設定して、Spring Data によって 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 アノテーションを付けます。

インデックスが有効になっている Spring アプリケーション
@SpringBootApplication
@PeerCacheApplication
@EnableEntityDefinedRegions
@EnableIndexing
class ServerApplication { .. }
@EnablingIndexing アノテーションは、@EnableEntityDefinedRegions も宣言されていない限り効果がありません。基本的に、インデックスはエンティティクラス型のフィールドまたはプロパティから定義されるため、エンティティクラスをスキャンして、エンティティのフィールドとプロパティにインデックスアノテーションが存在するかどうかを確認する必要があります。このスキャンを行わないと、インデックスアノテーションを見つけることができません。また、スキャンの範囲を制限することを強くお勧めします。

Spring Data では Apache Geode リポジトリに対する Lucene クエリは(まだ)サポートされていませんが、SDG は使い慣れた Spring テンプレート設計パターンを使用することで、Apache Geode に対する Lucene クエリを包括的にサポートしています。

最後に、インデックスを使用する際に留意すべきいくつかの追加のヒントを述べて、このセクションを締めくくります。

  • OQL クエリを実行するために OQL インデックスは必要ありませんが、Lucene テキストベースの検索を実行するには Lucene インデックスが必要です。

  • OQL インデックスはディスク上に保存されず、メモリ上にのみ保持されます。そのため、Apache Geode ノードを再起動すると、インデックスを再構築する必要があります。

  • インデックスの維持管理に伴うオーバーヘッドにも注意が必要です。特に、インデックスはメモリ上にのみ保存され、リージョンエントリが更新される際にはその影響が大きくなります。インデックスの「メンテナンス」は非同期タスクとして設定 [Apache] (英語) できます。

インデックスを再構築する必要がある Spring アプリケーションを再起動するときに使用できるもう 1 つの最適化は、最初にすべてのインデックスを事前に定義し、次にすべて一度に作成することです。これは、Apache Geode の Spring Data では、Spring コンテナーがリフレッシュされるときに行われます。

事前にインデックスを定義しておき、@EnableIndexing アノテーションの define 属性を true に設定することで、一度にすべてのインデックスを作成できます。

詳細については、Apache Geode のユーザーガイドの “複数のインデックスを一度に作成する” [Apache] (英語) を参照してください。

適切に設計されていないインデックスはメリットよりもデメリットをもたらす可能性があるため、適切なインデックスを作成することは重要なタスクです。

構成オプションの完全なリストについては、@Indexed (Javadoc) アノテーションと @LuceneIndexed (Javadoc) アノテーションの Javadoc を参照してください。

Apache Geode OQL クエリの詳細については、こちら [Apache] (英語) を参照してください。

Apache Geode インデックスに関する詳細はこちら [Apache] (英語) を参照してください。

Apache Geode Lucene クエリの詳細については、こちら [Apache] (英語) を参照してください。

6.13. 継続クエリの設定

Apache Geode のもう一つの非常に重要かつ便利な機能は継続的なクエリ [Apache] (英語) です。

インターネットに接続されたモノの世界では、イベントやデータストリームはあらゆる場所から発生します。大量のデータストリームを処理・処理し、イベントにリアルタイムで反応できることは、多くのアプリケーションにとってますます。重要な要件となっています。自動運転車もその一例です。リアルタイムでデータを受信し、フィルタリング、変換、分析し、それに基づいて行動できることは、リアルタイムアプリケーションの重要な差別化要因であり、特徴です。

幸いなことに、Apache Geode はこの点において時代を先取りしていました。継続的クエリ(CQ)を使用することで、クライアントアプリケーションは関心のあるデータやイベントを表現し、発生したイベントを処理・処理するためのリスナーを登録できます。クライアントアプリケーションが関心を持つ可能性のあるデータは OQL クエリとして表現され、クエリ述語は関心のあるデータをフィルタリングまたは識別するために使用されます。データが変更または追加され、登録された CQ のクエリ述語で定義された条件に一致すると、クライアントアプリケーションに通知されます。

Spring Data for Apache Geode を使用すると、Apache Geode の複雑な設定なしに、CQ を簡単に定義および登録でき、関連するリスナーを使用して CQ イベントを処理できます。SDG の新しいアノテーションベースの CQ 設定は、既存の継続クエリリスナーコンテナーの継続クエリサポートに基づいています。

たとえば、ある書籍パブリッシャーが Book のオーダー(需要)が現在の在庫(供給)を上回った場合に通知を受け取りたいとします。その場合、パブリッシャーの出力アプリケーションには次のような CQ を登録します。

CQ とリスナーが登録された Spring ClientCache アプリケーション。
@SpringBootApplication
@ClientCacheApplication(subcriptionEnabled = true)
@EnableContinuousQueries
class PublisherPrintApplication {

    @ContinuousQuery(name = "DemandExceedsSupply", query =
       "SELECT book.* FROM /Books book, /Inventory inventory
        WHERE book.title = 'How to crush it in the Book business like Amazon"
        AND inventory.isbn = book.isbn
        AND inventory.available < (
            SELECT sum(order.lineItems.quantity)
            FROM /Orders order
            WHERE order.status = 'pending'
            AND order.lineItems.isbn = book.isbn
        )
    ")
    void handleSupplyProblem(CqEvent event) {
        // start printing more books, fast!
    }
}

継続的なクエリを有効にするには、アプリケーションクラスに @EnableContinuousQueries アノテーションを付けます。

継続的クエリの定義は、Spring、@Component でアノテーションされた POJO クラスメソッドに @ContinuousQuery アノテーションを付与することで実現されます(SDG の Function アノテーション付き POJO メソッドと同様の方法です)。@ContinuousQuery アノテーションを使用して継続的クエリで定義された POJO メソッドは、クエリ述語に一致するデータが追加または変更されるたびに呼び出されます。

さらに、POJO メソッドのシグネチャーは、ContinuousQueryListener および ContinuousQueryListenerAdapter のセクションで概説されている要件に準拠する必要があります。

使用可能な属性と構成設定の詳細については、@EnableContinuousQueries (Javadoc) および @ContinuousQuery (Javadoc) アノテーションの Javadoc を参照してください。

Apache Geode の継続的クエリサポートに関する Spring Data の詳細については、こちらを参照してください。

Apache Geode の継続クエリに関する詳細は、こちら [Apache] (英語) を参照してください。

6.14. Spring のキャッシュ抽象化の設定

Spring Data for Apache Geode を使用すると、Apache Geode を Spring のキャッシュ抽象化におけるキャッシュプロバイダとして使用できます。

Spring のキャッシュ抽象化では、キャッシングアノテーション(@Cacheable など)は、潜在的に高負荷な操作を呼び出す前にキャッシュ検索を実行するキャッシュを識別します。アプリケーションサービスメソッドの結果は、操作が呼び出された後にキャッシュされます。

Apache Geode の Spring Data では、Spring の Cache は Apache Geode のリージョンに直接対応します。このリージョンは、キャッシュアノテーションが付与されたアプリケーションサービスメソッドが呼び出される前に存在している必要があります。これは、サービス操作で使用するキャッシュを識別する Spring のキャッシュアノテーション(つまり、@Cacheable、@CachePut、@CacheEvict)にも当てはまります。

たとえば、パブリッシャーの販売時点管理 (PoS) アプリケーションには、次の例に示すように、販売取引中に Book の Price を判別または検索する機能がある場合があります。

@Service
class PointOfSaleService

  @Cacheable("BookPrices")
  Price runPriceCheckFor(Book book) {
      ...
  }

  @Transactional
  Receipt checkout(Order order) {
      ...
  }

  ...
}

Spring のキャッシュ抽象化を使用して Apache Geode に Spring Data を使用する際の作業を容易にするために、アノテーションベースの構成モデルに 2 つの新しい機能が追加されました。

次の Spring キャッシュ構成を検討してください。

Apache Geode をキャッシュプロバイダーとして使用してキャッシュを有効にする
@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(..);
  }
}

Apache Geode の新機能に Spring Data を使用すると、同じキャッシュ構成を次のように簡素化できます。

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 にリージョンを作成します。

作成されたリージョンは、そのリージョンを作成したアプリケーションプロセスに対してローカルです。アプリケーションがピア Cache の場合、リージョンはアプリケーションノード上にのみ存在します。アプリケーションが ClientCache の場合、SDG はクライアント PROXY リージョンを作成し、同じ名前のリージョンがクラスタ内のサーバー上にすでに存在しているものと想定します。

SDG は、実行時に操作で使用されるキャッシュを解決するために Spring CacheResolver を使用するサービスメソッドに必要なキャッシュを判別できません。
SDG は、アプリケーションサービスコンポーネントにおける JCache(JSR-107)キャッシュアノテーションもサポートしています。JCache キャッシュアノテーションの代わりに使用できる同等の Spring キャッシュアノテーションについては、コア Spring Framework リファレンスガイドを参照してください。

Spring のキャッシュ抽象化で Apache Geode をキャッシュプロバイダーとして使用する方法の詳細については、“Spring キャッシュ抽象化のサポート” セクションを参照してください。

Spring のキャッシュ抽象化に関する詳細は、こちらを参照してください。

6.15. クラスタ構成プッシュの構成

これは、Apache Geode にとって Spring Data の最もエキサイティングな新機能かもしれません。

クライアントアプリケーションクラスに @EnableClusterConfiguration アノテーションが付与されている場合、クライアントアプリケーションによって Spring コンテナー内で Bean として定義および宣言されたすべてのリージョンまたはインデックスが、クライアントが接続しているサーバークラスタに「プッシュ」されます。さらに、この「プッシュ」は、HTTP 使用時にクライアントからプッシュされた構成を Apache Geode が記憶するように実行されます。クラスタ内のすべてのノードがダウンした場合、ノードは以前と同じ構成で復旧します。新しいサーバーがクラスタに追加された場合も、同じ構成が保持されます。

ある意味、この機能は、Gfsh を使用してクラスター内のすべてのサーバーにリージョンとインデックスを手動で作成する場合とほとんど変わりません。ただし、Apache Geode 用の Spring Data を使用すると、リージョンとインデックスを作成するために Gfsh を使用する必要がなくなります。Apache Geode 用の Spring Data の機能が有効になっている Spring Boot アプリケーションには、リージョンとインデックスの作成に必要なすべての構成メタデータがすでに含まれています。

Spring Data リポジトリ抽象化を使用する場合、アプリケーションに必要なすべての領域 (@Region アノテーション付きエンティティクラスによって定義されるものなど) とインデックス (@Indexed アノテーション付きエンティティフィールドおよびプロパティによって定義されるものなど) がわかります。

Spring のキャッシュ抽象化を使用すると、アプリケーションのサービスコンポーネントに必要なキャッシュアノテーションで識別されたすべてのキャッシュのリージョンもすべて把握されます。

本質的には、アノテーションメタデータ、Java、XML などで表現されているか、構成、マッピング、その他の目的であるかに関係なく、Spring Framework のすべての API と機能を使用してアプリケーションを開発するだけで、必要な情報はすべて提供されていることになります。

重要なのは、フレームワークの機能とサポートインフラストラクチャ (Spring のキャッシュ抽象化、Spring Data リポジトリ、Spring のトランザクション管理など) を使用しながら、アプリケーションのビジネスロジックに集中でき、Apache Geode 用の Spring Data が、これらのフレームワーク機能に必要な Apache Geode のすべての接続機能をユーザーに代わって処理することです。

クライアントからクラスタ内のサーバーへ設定をプッシュし、クラスタにそれを記憶させる機能は、Apache Geode のクラスタ構成 [Apache] (英語) サービスを使用することで部分的に実現されています。Apache Geode のクラスタ設定サービスは、ユーザーがシェルからクラスタに対して発行したスキーマ関連の変更(たとえば、gfsh> create region --name=Example --type=PARTITION)を記録するために Gfsh が使用するサービスと同じです。

もちろん、クラスターは前回の実行時にクライアントからプッシュされた設定を「記憶」している可能性があるため、Spring Data for Apache Geode は、サーバーにすでに定義されているリージョンやインデックスを侵害しないように注意しています。これは、たとえばリージョンにすでにデータが含まれている場合などに特に重要です。

現在、既存のリージョンまたはインデックスの定義を上書きするオプションはありません。リージョンまたはインデックスを再作成するには、まず Gfsh を使用してリージョンまたはインデックスを破棄し、クライアントアプリケーションを再起動して設定をサーバーに再度プッシュする必要があります。または、Gfsh を使用してリージョンとインデックスを手動で(再)定義することもできます。
Gfsh とは異なり、Spring Data for Apache Geode は、クライアントからサーバー側へのリージョンとインデックスの作成のみをサポートします。高度な設定やユースケースでは、Gfsh を使用して(サーバー側の)クラスターを管理する必要があります。
この機能を使用するには、Spring、Apache Geode、ClientCache アプリケーションのクラスパスで org.springframework:spring-web 依存関係を明示的に宣言する必要があります。

次の構成で表現される電力を考慮してください。

Spring ClientCache アプリケーション
@SpringBootApplication
@ClientCacheApplication
@EnableCachingDefinedRegions
@EnableEntityDefinedRegions
@EnableIndexing
@EnableGemfireCaching
@EnableGemfireRepositories
@EnableClusterConfiguration
class ClientApplication { .. }

Apache Geode ClientCache インスタンス、Spring Data リポジトリ、Apache Geode をキャッシュプロバイダーとする Spring のキャッシュ抽象化 (リージョンとインデックスはクライアント上で作成されるだけでなく、クラスター内のサーバーにプッシュされます) を備えた Spring Boot アプリケーションが即座に提供されます。

そこからは、次の操作を実行するだけです。

  • マッピングとインデックスアノテーションが付けられたアプリケーションのドメインモデルオブジェクトを定義します。

  • 各エンティティ型に対する基本的なデータアクセス操作と簡単なクエリをサポートするために、リポジトリインターフェースを定義します。

  • エンティティをトランザクションするビジネスロジックを含むサービスコンポーネントを定義します。

  • キャッシュ、トランザクション動作などを必要とするサービスメソッドに適切なアノテーションを宣言します。

この場合、アプリケーションのバックエンドサービス(Apache Geode など)に必要なインフラストラクチャや接続機能は考慮されません。データベースユーザーにも同様の機能があります。現在、Spring および Apache Geode の開発者にも同様の機能が提供されています。

次の Spring Data と Apache Geode アノテーションを組み合わせると、このアプリケーションはほとんど労力をかけずに実際に動作し始めます。

  • @EnableContinuousQueries

  • @EnableGemfireFunctionExecutions

  • @EnableGemfireCacheTransactions

詳細については、@EnableClusterConfiguration アノテーション Javadoc を参照してください。

6.16. SSL の設定

ネットワーク経由で転送されるデータを直列化するのと同様に重要なのは、転送中のデータのセキュリティを確保することです。もちろん、Java でこれを実現する一般的な方法は、Secure Sockets Extension (SSE) と Transport Layer Security (TLS) を使用することです。

SSL を有効にするには、次のようにアプリケーションクラスに @EnableSsl アノテーションを追加します。

SSL 対応の Spring ClientCache アプリケーション
@SpringBootApplication
@ClientCacheApplication
@EnableSsl
public class ClientApplication { .. }

次に、キーストア、ユーザー名 / パスワードなど、必要な SSL 構成属性またはプロパティを設定する必要があります。

異なる Apache Geode コンポーネント (GATEWAY、HTTP、JMX、LOCATOR、SERVER) を SSL で個別に構成することも、CLUSTER 列挙値を使用して SSL を使用するようにまとめて構成することもできます。

次のように、ネストされた @EnableSsl アノテーション、Component 列挙からの列挙値を持つ components 属性を使用して、SSL 構成設定を適用する Apache Geode コンポーネントを指定できます。

コンポーネントによって SSL が有効になっている Spring ClientCache アプリケーション
@SpringBootApplication
@ClientCacheApplication
@EnableSsl(components = { GATEWAY, LOCATOR, SERVER })
public class ClientApplication { .. }

さらに、対応するアノテーション属性または関連する構成プロパティを使用して、コンポーネントレベルの SSL 構成 (ciphers、protocols、keystore/truststore 情報) を指定することもできます。

詳細については、@EnableSsl アノテーション Javadoc を参照してください。

Apache Geode の SSL サポートに関する詳細は、こちら [Apache] (英語) を参照してください。

6.17. セキュリティの構成

アプリケーションのセキュリティは間違いなく非常に重要であり、Apache Geode 用の Spring Data は、Apache Geode クライアントとサーバーの両方のセキュリティを保護するための包括的なサポートを提供します。

最近、Apache Geode は認証と認可を処理するための新しい統合セキュリティ [Apache] (英語) フレームワーク(従来の認証・認可セキュリティモデルに代わる)を導入しました。この新しいセキュリティフレームワークの主な機能と利点の一つは、Apache Shiro (英語) と統合することで、認証と認可の両方のリクエストを Apache Shiro に委譲し、セキュリティを強化できることです。

このセクションの残りの部分では、Apache Geode 用の Spring Data が 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] (英語) メソッドでインスタンスを設定することもできます。

  • アプリケーションに定義されたユーザー、ロール、権限を使用して Apache Shiro shiro.ini [Apache] (英語) ファイルを作成し、次にこの shiro.ini ファイルを参照するように Apache Geode security-shiro-init プロパティを設定します。このファイルは CLASSPATH で使用できる必要があります。

  • Apache Shiro のみを使用して、Apache Geode の新しい @EnableSecurity アノテーション用に Spring Boot アプリケーションクラスに Spring Data アノテーションを付け、アプリケーションのセキュリティメタデータ (承認されたユーザー、ロール、権限) にアクセスするための Spring コンテナー内の Bean として 1 つ以上の Apache Shiro Realms [Apache] (英語) を定義します。

最初のアプローチの問題は、独自の SecurityManager を実装する必要があることです。これは非常に面倒で、エラーが発生しやすい可能性があります。カスタム SecurityManager を実装すると、LDAP や独自の内部データソースなど、メタデータを格納するデータソースからセキュリティメタデータにアクセスできる柔軟性が得られます。しかし、この問題は、より広く知られており、Apache Geode に特化していない Apache Shiro Realms を設定して使用することですでに解決されています。

アプリケーション固有のカスタム SecurityManager を実装する方法の 1 つとして、Apache Geode の認証 [Apache] (英語) および認可 [Apache] (英語) のセキュリティ例を参照してください。ただし、これは強く推奨されません。

2 つ目のアプローチ、Apache Shiro INI ファイルを使用する方法は、わずかに優れていますが、それでもまず INI ファイルの形式に精通している必要があります。また、INI ファイルは静的であるため、実行時に簡単に更新することはできません。

3 番目のアプローチは、広く知られ、業界で受け入れられている概念 (つまり、Apache Shiro のセキュリティフレームワーク) に準拠しており、次の例に示すようにセットアップが簡単なため、最も理想的です。

Apache Shiro を使用した Spring サーバーアプリケーション
@SpringBootApplication
@CacheServerApplication
@EnableSecurity
class ServerApplication {

  @Bean
  PropertiesRealm shiroRealm() {

      PropertiesRealm propertiesRealm = new PropertiesRealm();

      propertiesRealm.setResourcePath("classpath:shiro.properties");
      propertiesRealm.setPermissionResolver(new GemFirePermissionResolver());

      return propertiesRealm;
  }
}
前の例で示した構成済みの Realm は、Apache Shiro でサポートされている Realms のいずれかに簡単に置き換えることができます。

Apache Shiro Realm のカスタム実装を作成することもできます。

詳細については、Apache Shiro の Realms に関するドキュメント [Apache] (英語) を参照してください。

Apache Shiro がクラスター内のサーバーの CLASSPATH 上にあり、1 つ以上の Apache Shiro Realms が Spring コンテナーで Bean として定義されている場合、Apache Geode の Spring Data はこの構成を検出し、@EnableSecurity アノテーションが使用されているときに Apache Shiro をセキュリティプロバイダーとして使用して Apache Geode サーバーを保護します。

Apache Shiro を使用した Apache Geode の新しい統合セキュリティフレームワークに対する Apache Geode のサポートに関する Spring Data の詳細については、この spring.io のブログ記事 (英語) を参照してください。

使用可能な属性と関連する構成プロパティの詳細については、@EnableSecurity (Javadoc) アノテーション Javadoc を参照してください。

Apache Geode のセキュリティに関する詳細は、こちら [Apache] (英語) を参照してください。

6.17.2. クライアントセキュリティの構成

Spring ベースの Apache Geode キャッシュクライアントアプリケーションをセキュリティで保護する方法についても説明しなければ、セキュリティに関する話は完結しません。

Apache Geode のクライアントアプリケーションのセキュリティ保護プロセスは、正直言ってかなり複雑です。簡単に言うと、以下の手順が必要です。

  1. org.apache.geode.security.AuthInitialize (英語) インターフェースの実装を提供します。

  2. アプリケーションが提供するカスタム AuthInitialize インターフェースを参照するには、Apache Geode security-client-auth-init (システム) プロパティを設定します。

  3. 独自の Apache Geode gfsecurity.properties ファイルにユーザー資格情報を指定します。

Apache Geode 用の Spring Data は、サーバーアプリケーションで使用されていたのと同じ @EnableSecurity アノテーションを使用することで、これらの手順をすべて簡素化します。つまり、同じ @EnableSecurity アノテーションがクライアントアプリケーションとサーバーアプリケーションの両方のセキュリティを処理します。この機能により、たとえば、組み込みのピア Cache アプリケーションから ClientCache アプリケーションに切り替える際に、ユーザーにとって容易になります。SDG アノテーションを @PeerCacheApplication または @CacheServerApplication から @ClientCacheApplication に変更するだけで完了です。

実際には、クライアント側で実行する必要があるのは次の操作だけです。

@EnableSecurity を使用した Spring クライアントアプリケーション
@SpringBootApplication
@ClientCacheApplication
@EnableSecurity
class ClientApplication { .. }

次に、次の例に示すように、必要なユーザー名とパスワードを含む使い慣れた Spring Boot application.properties ファイルを定義すれば、設定は完了です。

必要なセキュリティ資格情報を含む Spring Boot application.properties ファイル
spring.data.gemfire.security.username=jackBlack
spring.data.gemfire.security.password=b@cK!nB1@cK
デフォルトでは、Spring Boot はアプリケーションの CLASSPATH のルートに application.properties ファイルを置くと、そのファイルを見つけられます。もちろん、Spring はリソースの抽象化を使ってリソースを見つけるための様々な方法をサポートしています。

使用可能な属性と関連する構成プロパティの詳細については、@EnableSecurity (Javadoc) アノテーション Javadoc を参照してください。

Apache Geode セキュリティに関する詳細はこちら [Apache] (英語) を参照してください。

6.18. 設定のヒント

次のヒントは、新しいアノテーションベースの構成モデルを最大限に活用できます。

6.18.1. 構成の構成

“クラスタ構成プッシュの構成” のセクションで見たように、Apache Geode または Apache Geode の Spring Data の多くの機能がアノテーションによって有効化されると、Spring、@Configuration、@SpringBootApplication クラスにも多くのアノテーションが付加されるようになります。このような状況では、設定を少し細分化していくのが理にかなっています。

たとえば、次の宣言を考えてみましょう。

キッチンシンク付き Spring ClientCache アプリケーション
@SpringBootApplication
@ClientCacheApplication
@EnableContinuousQueries
@EnableCachingDefinedRegions
@EnableEntityDefinedRegions
@EnableIndexing
@EnableGemfireCacheTransactions
@EnableGemfireCaching
@EnableGemfireFunctionExecutions
@EnableGemfireRepositories
@EnableClusterConfiguration
class ClientApplication { .. }

この構成は、次のように関心事ごとに分類できます。

Spring ClientCache アプリケーションとキッチンシンクの起動
@SpringBootApplication
@Import({ GemFireConfiguration.class, CachingConfiguration.class,
    FunctionsConfiguration.class, QueriesConfiguration.class,
    RepositoriesConfiguration.class })
class ClientApplication { .. }

@ClientCacheApplication
@EnableClusterConfiguration
@EnableGemfireCacheTransactions
class GemFireConfiguration { .. }

@EnableGemfireCaching
@EnableCachingDefinedRegions
class CachingConfiguration { .. }

@EnableGemfireFunctionExecutions
class FunctionsConfiguration { .. }

@EnableContinuousQueries
class QueriesConfiguration {

   @ContinuousQuery(..)
   void processCqEvent(CqEvent event) {
       ...
   }
}

@EnableEntityDefinedRegions
@EnableGemfireRepositories
@EnableIndexing
class RepositoriesConfiguration { .. }

Spring Framework にとっては問題ではありませんが、次にコードを保守する必要がある人 (将来のある時点ではあなたかもしれません) のために、読みやすさを重視することを一般に推奨します。

6.18.2. 追加の構成ベースのアノテーション

次の SDG アノテーションについては、このリファレンスドキュメントでは説明されていません。これは、アノテーションが Apache Geode の非推奨の機能をサポートしているため、またはアノテーションが提供する機能を実現するためのより優れた代替方法があるためです。

  • @EnableAuth: Apache Geode の古い認証および認可セキュリティモデルを有効にします。(非推奨。Apache Geode の新しい統合セキュリティフレームワークは、"セキュリティの構成" に従って、SDG の @EnableSecurity アノテーションを使用することで、クライアントとサーバーの両方で有効にできます。)

  • @EnableAutoRegionLookup: 推奨しません。基本的に、このアノテーションは、外部構成メタデータ(サーバーに適用された場合の cache.xml やクラスタ構成など)で定義されたリージョンを検索し、それらのリージョンを Spring コンテナーのビーンとして自動的に登録します。このアノテーションは、SDG の XML 名前空間の <gfe:auto-region-lookup> 要素に対応します。詳細はこちらを参照してください。Spring を使用する場合は Spring 構成を、Apache Geode を使用する場合は Spring Data 構成を推奨します。代わりに "領域の構成" と "クラスタ構成プッシュの構成" を参照してください。

  • @EnableBeanFactoryLocator: SDG GemfireBeanFactoryLocator 機能を有効にします。この機能は、外部構成メタデータ (たとえば cache.xml) を使用する場合にのみ役立ちます。例: cache.xml で定義されたリージョンに CacheLoader を定義した場合でも、Spring 構成で定義されたリレーショナルデータベース DataSource Bean などを使用して、この CacheLoader を自動ワイヤリングできます。このアノテーションは、この SDG 機能を活用しており、cache.xml ファイルなどの大量のレガシー構成メタデータがある場合に役立つ可能性があります。

  • @EnableGemFireAsLastResource: グローバル - JTA トランザクション管理で Apache Geode と議論されました。

  • @EnableMcast: UDP ベースのマルチキャストネットワークを使用する Apache Geode の古いピア検出メカニズムを有効にします。( 非推奨。代わりに Apache Geode ロケータを使用してください。"埋め込みロケーターの設定" を参照してください)

  • @EnableRegionDataAccessTracing: デバッグに役立ちます。このアノテーションは、Spring コンテナー内で Bean として宣言されたすべての Region をプロキシする AOP アスペクトを登録し、Region 操作をインターセプトしてイベントをログに記録することで、Region で実行されるすべてのデータアクセス操作のトレースを可能にします。

6.19. 結論

前のセクションで説明したように、Apache Geode 用の Spring Data の新しいアノテーションベースの構成モデルは非常に強力です。Apache Geode を Spring と組み合わせて使用する際に、迅速かつ簡単に 使い始めることができるというゴールが達成されることを願っています。

新しいアノテーションを使用する場合でも、Java 構成または XML 構成を引き続き使用できることに注意してください。Spring の @Import (Javadoc) および @ImportResource (Javadoc) アノテーションを Spring、@Configuration、@SpringBootApplication クラスで使用することで、これら 3 つのアプローチを組み合わせることもできます。Spring Data が Apache Geode にアノテーションのいずれかを使用して提供する Bean 定義を明示的に指定した瞬間、アノテーションベースの構成は破棄されます。

場合によっては、Configurers のように、アノテーションだけでは簡単に表現できない、あるいは実現できない複雑な設定ロジックや条件付き設定ロジックを処理するために、Java 設定にフォールバックする必要があるかもしれません。心配不要です。これは想定内の動作です。

例: Java または XML による設定が必要となるもう一つのケースは、Apache Geode WAN コンポーネントを設定する場合です。現在、これらのコンポーネントにはアノテーション設定のサポートがありません。ただし、WAN コンポーネントの定義と登録には、Spring の @Configuration または @SpringBootApplication クラスの Java 構成で org.springframework.data.gemfire.wan.GatewayReceiverFactoryBean および org.springframework.data.gemfire.wan.GatewaySenderFactoryBean API クラスを使用するだけで済みます(推奨)。

これらのアノテーションはあらゆる状況に対応できるものではありません。特に開発段階において、できるだけ早く簡単 に 使い始められるようにするためのものです。

これらの新しい機能を楽しんでいただければ幸いです。

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

@ClientCacheApplication Javadoc を参照してください。

詳細については、Spring を使用した Apache Geode アプリケーションの構成を参照してください。

6.20.2. ピア Cache アプリケーションを構成する

Apache Geode ピア Cache アプリケーションを構成およびブートストラップするには、次を使用します。

@SpringBootApplication
@PeerCacheApplication
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
CacheServer を有効にして、ClientCache アプリケーションがこのサーバーに接続できるようにするには、@PeerCacheApplication アノテーションを @CacheServerApplication アノテーションに置き換えるだけです。これにより、CacheServer が "localhost" 上で実行され、40404 のデフォルトの CacheServer ポートをリッスンするようになります。

@CacheServerApplication Javadoc を参照してください。

@PeerCacheApplication Javadoc を参照してください。

詳細については、Spring を使用した Apache Geode アプリケーションの構成を参照してください。

6.20.3. 埋め込みロケーターを構成する

次のように、Spring @PeerCacheApplication または @CacheServerApplication クラスに @EnableLocator のアノテーションを付けて、デフォルトのロケータポート 10334 でリッスンしているすべての NIC にバインドされた埋め込みロケータを起動します。

@SpringBootApplication
@CacheServerApplication
@EnableLocator
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
@EnableLocator は Apache Geode サーバーアプリケーションでのみ使用できます。

@EnableLocator Javadoc を参照してください。

詳細については、埋め込みロケーターの設定を参照してください。

6.20.4. 組み込みマネージャーを構成する

次のように、Spring @PeerCacheApplication または @CacheServerApplication クラスに @EnableManager のアノテーションを付けて、デフォルトのマネージャーポート 1099 でリッスンしているすべての NIC にバインドされた組み込みマネージャーを起動します。

@SpringBootApplication
@CacheServerApplication
@EnableManager
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
@EnableManager は Apache Geode サーバーアプリケーションでのみ使用できます。

@EnableManager Javadoc を参照してください。

詳細については、組み込みマネージャーの設定を参照してください。

6.20.5. 組み込み HTTP サーバーを構成する

次のように、Spring @PeerCacheApplication または @CacheServerApplication クラスに @EnableHttpService アノテーションを付けて、ポート 7070 でリッスンする組み込み HTTP サーバー (Jetty) を起動します。

@SpringBootApplication
@CacheServerApplication
@EnableHttpService
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
@EnableHttpService は Apache Geode サーバーアプリケーションでのみ使用できます。

@EnableHttpService Javadoc を参照してください。

詳細については、組み込み HTTP サーバーの設定を参照してください。

6.20.6. 組み込み Memcached サーバーを構成する

次のように、Spring @PeerCacheApplication または @CacheServerApplication クラスに @EnableMemcachedServer アノテーションを付けて、ポート 11211 でリッスンする組み込み Memcached サーバー (Gemcached) を起動します。

@SpringBootApplication
@CacheServerApplication
@EnableMemcachedServer
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
@EnableMemcachedServer は Apache Geode サーバーアプリケーションでのみ使用できます。

@EnableMemcachedServer Javadoc を参照してください。

詳細については、組み込み Memcached サーバーの設定 (ジェムキャッシュ) を参照してください。

6.20.7. 組み込み Redis サーバーを構成する

次のように、Spring @PeerCacheApplication または @CacheServerApplication クラスに @EnableRedisServer のアノテーションを付けて、ポート 6379 でリッスンする組み込み Redis サーバーを起動します。

@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 モジュールを明示的に宣言する必要があります。

@EnableRedisServer Javadoc を参照してください。

詳細については、組み込み 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 のみを対象としています。

@EnableLogging Javadoc を参照してください。

詳細については、ロギングの構成を参照してください。

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

@EnableStatistics Javadoc を参照してください。

詳細については、統計情報の設定を参照してください。

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 を有効にするには、次のように、Spring、Apache Geode クライアントまたはサーバーアプリケーションクラスに @EnableSsl アノテーションを付けます。

@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 を必要とするシステムの特定のコンポーネントを構成できます。オプションで、"ALL" を使用して、Apache Geode のすべてのコンポーネントが SSL を使用するように指定できます。

@EnableSsl Javadoc を参照してください。

詳細については、SSL の設定を参照してください。

6.20.12. セキュリティを構成する

Apache Geode セキュリティを有効にするには、次のように、Spring、Apache Geode クライアントまたはサーバーアプリケーションクラスに @EnableSecurity アノテーションを付けます。

@SpringBootApplication
@ClientCacheApplication
@EnableSecurity
public class ClientApplication {

  public static void main(String[] args) {
    SpringApplication.run(ClientApplication.class, args);
  }
}
サーバー側で、認証資格情報へのアクセスを設定する必要があります。Apache Geode SecurityManager [Apache] (英語) インターフェースを実装するか、1 つ以上の Apache Shiro Realms を宣言することができます。詳細については、サーバーセキュリティの構成を参照してください。
クライアント側では、ユーザー名とパスワードを設定する必要があります。詳細についてはクライアントセキュリティの構成を参照してください。

@EnableSecurity Javadoc を参照してください。

詳細については、セキュリティの構成を参照してください。

6.20.13. Apache Geode プロパティの構成

機能指向の SDG 構成アノテーションでカバーされていないその他の低レベルの Apache Geode プロパティを構成するには、次のように、Spring、Apache Geode クライアントまたはサーバーアプリケーションクラスに @GemFireProperties アノテーションを付けます。

@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] (英語) を参照してください。

@EnableGemFireProperties Javadoc を参照してください。

詳細については、Apache Geode プロパティの設定を参照してください。

6.20.14. キャッシュの設定

Spring のキャッシュ抽象化で Apache Geode をキャッシュプロバイダーとして使用し、アプリケーションサービスコンポーネントに必要なキャッシュの Apache Geode 領域を SDG が自動的に作成するようにするには、次のように、Spring、Apache Geode クライアントまたはサーバーアプリケーションクラスに @EnableGemfireCaching および @EnableCachingDefinedRegions のアノテーションを付けます。

@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 はオプションです。つまり、必要に応じて手動でリージョンを定義することができます。

@EnableCachingDefinedRegions Javadoc を参照してください。

@EnableGemfireCaching Javadoc を参照してください。

詳細については、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;

import ...;

@Region("Books")
public class Book {

  @Id
  private ISBN isbn;

  @Indexed;
  private Author author;

  @Indexed
  private LocalDate published;

  @LuceneIndexed
  private String title;

}
@Region("Books") エンティティクラスアノテーションは、@EnableEntityDefinedRegions によってアプリケーションに必要なリージョンを決定するために使用されます。詳細については、型固有の領域の設定および POJO マッピングを参照してください。

最後に、次のように、Books を永続化してアクセスするための簡単なクエリを使用して CRUD リポジトリを定義します。

package example.app.repo;

import ...;

public interface BookRepository extends CrudRepository {

  List<Book> findByAuthorOrderByPublishedDesc(Author author);

}
詳細については、Spring Data for Apache Geode Repositories を参照してください。

@EnableEntityDefinedRegions Javadoc を参照してください。

@EnableGemfireRepositories Javadoc を参照してください。

@EnableIndexing Javadoc を参照してください。

@Region Javadoc を参照してください。

@Indexed Javadoc を参照してください。

@LuceneIndexed Javadoc を参照してください。

詳細については、領域の構成を参照してください。

詳細については、Spring Data for Apache Geode Repositories を参照してください。

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

}

@EnableGemfireFunctions Javadoc を参照してください。

@GemfireFunction Javadoc を参照してください。

@EnableGemfireFunctionExecutions Javadoc を参照してください。

詳細については、関数実行のアノテーションサポートを参照してください。

6.20.18. 継続的クエリを構成する

リアルタイムのイベントストリーム処理は、データ集約型アプリケーションにおいて、主にユーザーからのリクエストにタイムリーに対応するために、ますます。重要なタスクになりつつあります。Apache Geode Continuous Query (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) {
    ...
  }
}

継続的な OQL クエリ (CQ) の述語と一致するように Customer データを変更するイベントが発生するたびに、process メソッドが呼び出されます。

Apache Geode CQ はクライアント側のみの機能です。

@EnableContinuousQueries Javadoc を参照してください。

@ContinuousQuery Javadoc を参照してください。

詳細については、継続的クエリ (CQ) および継続クエリの設定を参照してください。

6.20.19. クラスタ構成を構成する

Apache Geode を Apache Geode ClientCache アプリケーションとして利用する Spring Data アプリケーションを開発する場合、クライアント / サーバートポロジーにおいて、クライアントと一致するようにサーバーを設定すると開発中に便利です。実際、Apache Geode では、クライアントに "/Example" PROXY Region が存在する場合、サーバーにも名前(例: "Example" )で一致する Region が存在することが想定されています。

Gfsh を使用して、アプリケーションに必要なすべてのリージョンとインデックスを作成することもでき、Apache Geode を使用して Spring Data アプリケーションを開発するときにすでに表現されている構成メタデータを実行時にプッシュすることもできます。

これは、メインアプリケーションクラスに @EnableClusterConfiguration(..) をアノテーションするのと同じくらい簡単です。

@EnableClusterConfiguration を使用する
@ClientCacheApplication
@EnableClusterConfiguration(useHttp = true)
class ClientApplication {
  ...
}
多くの場合、クライアント / サーバートポロジを使用する場合、特に本番環境では、クラスターのサーバーは Gfsh を使用して起動されます。その場合、設定メタデータ(例: リージョンやインデックスの定義)をクラスターに送信するには、HTTP(S) を使用するのが一般的です。HTTP を使用すると、設定メタデータはクラスター内のマネージャーに送信され、クラスター内のサーバーノード全体に一貫して配布されます。
@EnableClusterConfiguration を使用するには、Spring アプリケーションクラスパスで org.springframework:spring-web 依存関係を宣言する必要があります。

@EnableClusterConfiguration Javadoc を参照してください。

詳細については、クラスタ構成プッシュの構成を参照してください。

6.20.20. GatewayReceivers を構成する

異なる Apache Geode クラスタ間のデータレプリケーションは、フォールトトレランスと高可用性(HA)を実現する上でますます。重要になっているメカニズムです。Apache Geode WAN レプリケーションは、1 つの Apache Geode クラスタから別の Apache Geode クラスタに、信頼性とフォールトトレラント性を備えた方法でデータを複製できるメカニズムです。

Apache Geode WAN レプリケーションでは、次の 2 つのコンポーネントを構成する必要があります。

  • 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 ノードでのみ構成できます。

@EnableGatewayReceiver Javadoc を参照してください。

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)で構成されています。さらに、2 つの GatewaySenders が両方のリージョンにサービスを提供するように構成されます。GatewaySender1 はレプリケートするように構成され、Region1’s data and `GatewaySender2 はリージョン 2 のデータをレプリケートするように構成されます。

示されているように、各 GatewaySender プロパティは各 EnableGatewaySender アノテーションで構成できます。

より汎用的な「デフォルト」プロパティアプローチも可能で、すべてのプロパティを EnableGatewaySenders アノテーションで設定します。この方法では、親アノテーションに汎用的なデフォルト値を設定し、必要に応じて子アノテーションでオーバーライドすることができます。以下に例を示します。

@CacheServerApplication
@EnableGatewaySenders(gatewaySenders = {
		@EnableGatewaySender(name = "GatewaySender", transportFilters = "transportBean1", regions = "Region2"),
		@EnableGatewaySender(name = "GatewaySender2")},
		manualStart = true, remoteDistributedSystemId = 2,
		diskSynchronous = false, batchConflationEnabled = true, parallel = true, persistent = true,
		diskStoreReference = "someDiskStore", orderPolicy = OrderPolicyType.PARTITION, alertThreshold = 1234, batchSize = 1002,
		eventFilters = "SomeEventFilter", batchTimeInterval = 2000, dispatcherThreads = 22, maximumQueueMemory = 400,
		socketBufferSize = 16384, socketReadTimeout = 4000, regions = { "Region1", "Region2" },
		transportFilters = { "transportBean2", "transportBean1" })
class MySpringApplication { .. }
regions 属性が空のまま、または未入力の場合、GatewaySender はアプリケーション内で構成されたすべての Region に自動的に接続されます。

@EnableGatewaySenders Javadoc および @EnableGatewaySender Javadoc を参照してください。

7. Apache Geode API の操作

Apache Geode のキャッシュとリージョンの設定が完了したら、アプリケーションオブジェクト内に注入して使用できるようになります。本章では、Spring のトランザクション管理機能および DAO 例外階層との統合について説明します。また、Apache Geode 管理対象オブジェクトへの依存性注入のサポートについても説明します。

7.1. GemfireTemplate

Spring が提供する他の多くの高レベル抽象化と同様に、Apache Geode 用の Spring Data は、Apache Geode のデータアクセス操作を簡素化するテンプレートを提供します。このクラスは、一般的な Region 操作を含む複数のメソッドを提供するだけでなく、GemfireCallback を使用することで、Apache Geode のチェック例外を処理せずに、ネイティブ Apache Geode API に対してコードを実行する機能も提供します。

テンプレートクラスには 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 メソッドと比較して、複数のリージョンにわたるクエリの実行や、射影の実行などが可能です。

find メソッドは、クエリが複数の項目を選択する場合 ( SelectResults 経由) に使用する必要があり、後者の findUnique は、名前が示すとおり、1 つのオブジェクトのみが返される場合に使用する必要があります。

7.2. 例外変換

新しいデータアクセステクノロジを使用するには、新しい API に対応するだけでなく、そのテクノロジに固有の例外を処理することも必要です。

例外処理に対応するため、Spring Framework は、独自の例外(通常は "checked" の例外)からアプリケーションを抽象化し、特定のランタイム例外のセットに絞り込む、技術に依存しない一貫性のある例外階層 (英語) を提供します。

Spring Framework のドキュメントに記載されているように、例外変換 (英語) は、@Repository アノテーションと AOP を用いて PersistenceExceptionTranslationPostProcessor Bean を定義することで、データアクセスオブジェクト(DAO)に透過的に適用できます。Apache Geode を使用する場合でも、CacheFactoryBean が宣言されている限り、同様の例外変換機能が有効になります。たとえば、<gfe:cache/> または <gfe:client-cache> 宣言を使用すると、例外変換機能が Spring インフラストラクチャによって自動的に検出され、適切に使用されます。

7.3. ローカル、キャッシュトランザクション管理

Spring Framework の最も人気のある機能の 1 つは、トランザクション管理 (英語) です。

Spring のトランザクション抽象化についてよくご存知でない場合は、Spring のトランザクション管理インフラストラクチャについてお読みになるこ (英語) とを強くお勧めします。Spring のトランザクション管理インフラストラクチャは、複数の API 間で透過的に動作する一貫したプログラミングモデルを提供し、プログラムによる設定と宣言による設定(最も一般的な方法)の両方が可能です。

Apache Geode、Apache Geode の Spring Data では、キャッシュごとに専用の PlatformTransactionManager が提供されており、これを宣言すると、Region 操作を Spring を通じてアトミックに実行できるようになります。

XML を使用したトランザクション管理を有効にする
<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 [Apache] (英語) およびドキュメント [Apache] (英語) を参照してください。

7.4. グローバル、JTA トランザクション管理

また、Apache Geode は、他の JTA リソースとともにコンテナー管理トランザクション (CMT) を使用して、Java EE アプリケーションサーバー (WebSphere アプリケーションサーバー (WAS) など) によって管理されるトランザクションなどのグローバル JTA ベースのトランザクションに参加することもできます。

しかし、他の多くの JTA 準拠リソース(ActiveMQ のような JMS メッセージブローカーなど)とは異なり、Apache Geode は XA 準拠リソースではありません。そのため、Apache Geode は 2 フェーズコミットプロトコルを実装しておらず、分散トランザクションを処理できないため、JTA トランザクション(準備フェーズ)における「最後のリソース」として位置付ける必要があります。

CMT に対応した多くの管理環境では、JTA 仕様で必須ではないものの、JTA ベースのトランザクションにおいて「ラストリソース」、つまり XA 非準拠のリソースのサポートが維持されています。XA 非準拠の「ラストリソース」の意味については、Red Hat のドキュメント (英語) を参照してください。実際、Red Hat の JBoss プロジェクトである Narayana (英語) は、そのような LGPL オープンソース実装の 1 つです。Narayana では、これを「ラストリソースコミット最適化」(LRCO)と呼んでいます。詳細はこちら (英語) を参照してください。

ただし、「ラストリソース」をサポートするオープンソース JTA トランザクション管理実装を備えたスタンドアロン環境で Apache Geode を使用している場合でも、管理された環境 (WAS などの Java EE AS など) を使用している場合でも、Apache Geode 用の Spring Data が対応します。

複数のトランザクションリソースが関与する JTA トランザクションにおいて、Apache Geode を「最後のリソース」として適切に使用するには、いくつかの手順を実行する必要があります。また、このような構成では、XA 非準拠のリソース(例: Apache Geode)は 1 つしか使用できません。

1) まず、Apache Geode のドキュメントにある手順 1 ~ 4 を完了する必要があります。

上記の #1 は、Spring [Boot ] および / または [ Apache Geode] アプリケーションのデータ ] とは独立しており、正常に完了する必要があります。

2) Apache Geode のドキュメント [Apache] (英語) のステップ 5 を参照すると、Apache Geode のアノテーションサポート用の Spring Data は、@EnableGemFireAsLastResource アノテーションを使用する際に、GemFireCache、copyOnRead [Apache] (英語) プロパティを設定しようとします。

ただし、この点に関して SDG の自動構成がうまくいかない場合は、<gfe:cache> または <gfe:client-cache> XML 要素の copy-on-read 属性を明示的に設定するか、JavaConfig の CacheFactoryBean クラスの copyOnRead プロパティを true に設定する必要があります。例:

ClientCache XML:

XML を使用して読み取り時のコピーを設定する (クライアント)
<gfe:client-cache ... copy-on-read="true"/>

ClientCache JavaConfig:

JavaConfig を使用して copyOnRead を設定する (クライアント)
@Bean
ClientCacheFactoryBean gemfireCache() {

  ClientCacheFactoryBean gemfireCache = new ClientCacheFactoryBean();

  gemfireCache.setCopyOnRead(true);

  return gemfireCache;
}

ピア Cache XML:

XML を使用して読み取り時のコピーを設定する (サーバー)
<gfe:cache ... copy-on-read="true"/>

ピア Cache JavaConfig :

JavaConfig を使用して copyOnRead を設定する (サーバー)
@Bean
CacheFactoryBean gemfireCache() {

  CacheFactoryBean gemfireCache = new CacheFactoryBean();

  gemfireCache.setCopyOnRead(true);

  return gemfireCache;
}
copy-on-read 属性または copyOnRead プロパティを明示的に設定する必要はありません。トランザクション管理を有効にすると、読み取り時にコピーが行われます。

3) この時点で、Apache Geode のドキュメント [Apache] (英語) の手順 6 ~ 8 をスキップして、Spring Data Geode に処理を任せます。必要なのは、Spring @Configuration クラスに Apache Geode の新しい @EnableGemFireAsLastResource アノテーション用の Spring Data アノテーションを付け、Spring のトランザクション管理インフラストラクチャと Apache Geode の @EnableGemFireAsLastResource アノテーション構成用の Spring Data を組み合わせるだけです。これでうまくいきます。

構成は次のようになります。…

@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;
}
ローカル、キャッシュトランザクション管理セクションの設定はここでは適用されません。Apache Geode の GemfireTransactionManager に Spring Data を使用することは、「グローバル」な JTA トランザクションではなく、「ローカルのみ」なキャッシュトランザクションに適用されます。この場合、SDG の GemfireTransactionManager は設定しません。Spring の JtaTransactionManager は上記のように設定してください。

Spring のトランザクション管理を JTA で使用する方法の詳細については、こちらを参照してください。

実際には、Apache Geode の @EnableGemFireAsLastResource アノテーションの Spring Data は、トランザクション操作中の適切なポイントで Apache Geode o.a.g.ra.GFConnectionFactory.getConnection() および o.a.g.ra.GFConnection.close() 操作を処理する 2 つのアスペクト Bean 定義を含む構成をインポートします。

具体的には、正しいイベントの順序は次のとおりです。

  1. jtaTransation.begin()

  2. GFConnectionFactory.getConnection()

  3. アプリケーションの @Transactional サービスメソッドを呼び出す

  4. jtaTransaction.commit() または jtaTransaction.rollback() のいずれか

  5. 最後に、GFConnection.close()

これは、アプリケーション開発者として、JTA API + Apache Geode API を自分で使用する必要がある場合に手動でコーディングする方法と一致しています。これは、Apache Geode の例 [Apache] (英語) で示されています。

ありがたいことに、Spring が面倒な作業をすべて引き受けてくれるため、適切な構成 (上記参照) を適用した後は、次の操作を行うだけで済みます。

サービスメソッドを @Transactional として宣言する
@Service
class MyTransactionalService {

  @Transactional
  public <Return-Type> someTransactionalServiceMethod() {
    // perform business logic interacting with and accessing multiple JTA resources atomically
  }

  ...
}

上記の #1 と #4 は、アプリケーションが @Transactional 境界に入ると (つまり、MyTransactionService.someTransactionalServiceMethod() が呼び出されると)、Spring の JTA ベースの PlatformTransactionManager によって適切に処理されます。

#2 と #3 は、@EnableGemFireAsLastResource アノテーションで有効になっている Apache Geode の新しいアスペクトのために Spring Data によって処理されます。

もちろん、#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 以降、Apache Geode Neumann/2.3 では、自動トランザクションイベントの公開を有効にできるようになりました。

@EnableGemfireCacheTransactions アノテーションを使用して、enableAutoTransactionEventPublishing 属性を true に設定します。デフォルトは false です。

自動トランザクションイベントの公開を有効にする
@EnableGemfireCacheTransactions(enableAutoTransactionEventPublishing = true)
class GeodeConfiguration { ... }

次に、AFTER_COMMIT または AFTER_ROLLBACK トランザクションフェーズ中にトランザクションイベントを処理するために、@TransactionalEventListener アノテーションが付けられた POJO メソッドを作成できます。

@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) が呼び出される時点で、トランザクションライフサイクル中に @TranactionalEventListener アノテーション付き POJO メソッドが呼び出される AbstractPlatformTransactionManager.triggerBeforeCommit(:TransactionStatus) 呼び出しの後であるためです。

自動トランザクションイベントパブリッシングを使用すると、アプリケーションの @Transactional または @Service メソッド内で applicationEventPublisher.publishEvent(..) メソッドを明示的に呼び出す必要はありません。

ただし、「コミット前」にトランザクションイベントを受け取りたい場合は、アプリケーション内で applicationEventPublisher.publishEvent(..) メソッド、@Transactional メソッド、@Service メソッドを呼び出す必要があります。詳細は上記の注記を参照してください。

7.7. 継続的クエリ (CQ)

Apache Geode が提供する強力な機能は継続的クエリ [Apache] (英語) (または CQ) です。

つまり、CQ を使用すると、開発者は OQL クエリを作成・登録し、Apache Geode に追加された新しいデータがクエリ述語に一致したときに自動的に通知を受け取ることができます。Apache Geode 用の Spring Data は、org.springframework.data.gemfire.listener パッケージとそのリスナーコンテナーを通じて CQ 専用のサポートを提供します。これは、Spring Framework の JMS 統合と機能と命名が非常に似ています。実際、Spring の JMS サポートに慣れているユーザーであれば、すぐに使いこなせるはずです。

基本的に、Apache Geode 用の Spring Data は、POJO 上のメソッドを CQ のエンドポイントとして使用できます。クエリを定義し、一致した場合に通知を受け取るメソッドを指定するだけです。残りの処理は Apache Geode 用の Spring Data が行います。これは Java EE のメッセージ駆動型 Bean スタイルに非常に似ていますが、Apache Geode に基づいており、基底クラスやインターフェースの実装は必要ありません。

現在、継続的クエリは Apache Geode のクライアント / サーバー構成でのみサポートされています。また、使用するクライアントプールではサブスクリプションが有効になっている必要があります。詳細については、Apache Geode のドキュメント [Apache] (英語) を参照してください。

7.7.1. 継続的クエリリスナーコンテナー

Apache Geode 用の Spring Data は、SDG の ContinuousQueryListenerContainer を使用して CQ 周辺のインフラストラクチャを管理することで、CQ イベントの作成、登録、ライフサイクル、ディスパッチを簡素化します。ContinuousQueryListenerContainer は、ユーザーに代わってすべての面倒な処理を実行します。EJB と JMS に精通しているユーザーにとって、Spring Data はメッセージ駆動型 POJO(MDP)を備えた Spring Framework のサポートに可能な限り近い設計になっているため、概念は馴染みやすいはずです。

SDG ContinuousQueryListenerContainer はイベント(またはメッセージ)リスナーコンテナーとして機能します。登録された CQ からイベントを受信し、そこに挿入された POJO を呼び出すために使用されます。リスナーコンテナーは、メッセージ受信のすべてのスレッド処理を担当し、リスナーへのディスパッチ処理を行います。EDP(イベント駆動型 POJO)とイベントプロバイダー間の仲介役として機能し、イベントを受信するための CQ の作成と登録、リソースの取得と解放、例外の変換などを行います。これにより、アプリケーション開発者は、イベントの受信(およびそれへの対応)に関連する(場合によっては複雑な)ビジネスロジックを記述し、定型的な Apache Geode インフラストラクチャに関する事項をフレームワークに委譲することができます。

リスナーコンテナーは完全にカスタマイズ可能です。開発者は、適切な java.util.concurrent.Executor (または Spring の TaskExecutor)を定義することで、CQ スレッドを使用してディスパッチ(同期配信)を実行するか、既存のプールから新しいスレッドを使用して非同期アプローチを実行するかを選択できます。負荷、リスナー数、ランタイム環境に応じて、開発者はエグゼキューターを変更または調整し、ニーズにより適切に対応する必要があります。特に、管理対象環境(アプリケーションサーバーなど)では、ランタイムを最大限に活用するために適切な TaskExecutor を選択することを強くお勧めします。

7.7.2. ContinuousQueryListener および ContinuousQueryListenerAdapter

ContinuousQueryListenerAdapter クラスは、Spring Data における Apache Geode CQ サポートの最終コンポーネントです。簡単に言うと、このクラスを使用すると、ほぼすべての実装クラスを最小限の制約で EDP として公開できます。ContinuousQueryListenerAdapter は、Apache Geode の CqListener [Apache] (英語) に似たシンプルなリスナーインターフェースである ContinuousQueryListener インターフェースを実装しています。

次のインターフェース定義を考えてみましょう。様々なイベント処理メソッドとそのパラメーターに注目してください。

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 インスタンスを介して任意のパラメーターを渡すことができます。

このセクションでは、cache.xml で定義されたこれらのプラガブルコンポーネントを Spring を使用して設定し、cache.xml で定義されたキャッシュ / リージョン設定を維持する方法について説明します。これにより、プラガブルコンポーネントは DataSources やその他の連携コンポーネントの場所や作成を気にすることなく、アプリケーションロジックに集中できるようになります。

ただし、グリーンフィールドプロジェクトを開始する場合は、キャッシュ、リージョン、その他のプラグ可能な Apache Geode コンポーネントを Spring で直接構成することをお勧めします。これにより、Declarable インターフェースやこのセクションで紹介する基本クラスを継承する必要がなくなります。

このアプローチの詳細については、次のサイドバーを参照してください。

Declarable コンポーネントを削除する

開発者は、リージョンの設定で記述されていたように、Spring を通じてカスタム型を完全に構成できます。これにより、開発者は Declarable インターフェースを実装する必要がなく、Spring IoC コンテナーのすべての機能(依存性注入だけでなく、ライフサイクル管理やインスタンス管理も含む)を活用できます。

Spring を使用して Declarable コンポーネントを構成する例として、次の宣言 (Declarable Javadoc [Apache] (英語) から取得) を検討します。

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

オブジェクトの解析、パラメーターの変換、初期化といったタスクを簡素化するため、Apache Geode 用の Spring Data は基本クラス(WiringDeclarableSupport)を提供しています。これにより、Apache Geode ユーザーオブジェクトをテンプレート Bean 定義を介して接続できます。テンプレート Bean 定義がない場合は、Spring IoC コンテナーを介して自動接続できます。この機能を利用するには、ユーザーオブジェクトは WiringDeclarableSupport を継承する必要があります。これにより、宣言されている BeanFactory が自動的に検出され、初期化プロセスの一環として接続が実行されます。

基本クラスはなぜ必要なのでしょうか ?

現在の Apache Geode リリースにはオブジェクトファクトリの概念がなく、宣言された型はそのままインスタンス化されて使用されます。つまり、Apache Geode の外部でオブジェクトの作成を管理する簡単な方法はありません。

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 から取得型など、様々な形態が考えられます。これらの要素は、DBLoader のコードに触れることなく、Spring コンテナーを通じて簡単に設定・変更できます。

7.9. Spring キャッシュ抽象化のサポート

Apache Geode 用の Spring Data は、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" )、つまり明示的な ID のない <gfe:cache> が使用されている場合、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、C++、.NET) 間で透過的に動作するだけでなく、標準の Java 直列化よりも高速でコンパクトな結果を提供します。

詳細については、PDX 直列化機能 [Apache] (英語) および PDX 直列化の内部構造 [Apache] (英語) を参照してください。

この章では、Apache Geode 用の Spring Data が Java での Apache Geode のカスタム直列化を簡素化および改善するさまざまな方法について説明します。

8.1. デシリアライズされたインスタンスの接続

直列化されたオブジェクトが一時データを持つことは、かなり一般的です。一時データは、多くの場合、特定の時点で存在するシステムまたは環境に依存します。たとえば、DataSource は環境に依存します。このような情報は特定の VM またはマシンにローカルであるため、直列化しても意味がなく、場合によっては危険です。このような場合に備えて、Apache Geode 用の Spring Data は、デシリアライズ中に Apache Geode によって作成される新しいインスタンスごとにワイヤリングを行う特別な Instantiator [Apache] (英語) を提供します。

このようなメカニズムにより、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>

上記の定義は、2 つのクラス(CustomTypeA と CustomTypeB)に対して 2 つの Instantiators を自動的に生成し、ユーザー ID 1025 と 1026 で Apache Geode に登録します。2 つの Instantiators はリフレクションの使用を避け、Java コードから直接インスタンスを作成します。

9. POJO マッピング

このセクションでは以下について説明します。

9.1. オブジェクトマッピングの基礎

このセクションでは、Spring Data オブジェクトマッピング、オブジェクト作成、フィールドとプロパティへのアクセス、可変性と不変性の基礎について説明します。このセクションは、基になるデータストア(JPA など)のオブジェクトマッピングを使用しない Spring Data モジュールにのみ適用されることに注意してください。また、インデックス、列名やフィールド名のカスタマイズなど、ストア固有のオブジェクトマッピングについては、ストア固有のセクションを参照してください。

Spring Data オブジェクトマッピングの中心的なロールは、ドメインオブジェクトのインスタンスを作成し、ストアネイティブデータ構造をそれらにマッピングすることです。つまり、2 つの基本的な手順が必要です。

  1. 公開されたコンストラクターの 1 つを使用したインスタンスの作成。

  2. すべての公開されたプロパティを具体化するインスタンスの設定。

9.1.1. オブジェクト作成

Spring Data は、その型のオブジェクトの具体化に使用される永続エンティティのコンストラクターを自動的に検出しようとします。解決アルゴリズムは次のように機能します。

  1. 引数なしのコンストラクターがある場合は、それが使用されます。他のコンストラクターは無視されます。

  2. 引数を取る単一のコンストラクターがある場合は、それが使用されます。

  3. 引数を取る複数のコンストラクターがある場合、Spring Data が使用するコンストラクターに @PersistenceConstructor のアノテーションを付ける必要があります。

値の解決は、コンストラクターの引数名がエンティティのプロパティ名と一致することを前提としています。つまり、マッピングのすべてのカスタマイズ(異なるデータストア列またはフィールド名など)を含む、プロパティが設定されるかのように解決が実行されます。また、これには、クラスファイルで使用可能なパラメーター名情報、またはコンストラクターに存在する @ConstructorProperties アノテーションのいずれかが必要です。

値の解決は、ストア固有の SpEL 式を使用した Spring Framework の @Value 値アノテーションを使用してカスタマイズできます。詳細については、ストア固有のマッピングに関するセクションを参照してください。

オブジェクト作成の詳細

リフレクションのオーバーヘッドを回避するために、Spring Data オブジェクトの作成では、デフォルトで実行時に生成されるファクトリクラスを使用します。これにより、ドメインクラスコンストラクターが直接呼び出されます。つまりこの例の型:

class Person {
  Person(String firstname, String lastname) { … }
}

実行時にこれと意味的に同等のファクトリクラスを作成します。

class PersonObjectInstantiator implements ObjectInstantiator {

  Object newInstance(Object... args) {
    return new Person((String) args[0], (String) args[1]);
  }
}

これにより、反射よりも約 10% パフォーマンスが向上します。ドメインクラスがこのような最適化の対象となるには、一連の制約に従う必要があります。

  • プライベートクラスであってはなりません

  • 非静的内部クラスであってはなりません

  • CGLib プロキシクラスであってはなりません

  • Spring Data で使用されるコンストラクターはプライベートであってはなりません

これらの条件のいずれかが一致する場合、Spring Data はリフレクションを介してエンティティのインスタンス化にフォールバックします。

9.1.2. プロパティ設定

エンティティのインスタンスが作成されると、Spring Data はそのクラスの残りのすべての永続プロパティを設定します。エンティティのコンストラクターによってすでに入力されていない場合(つまり、コンストラクターの引数リストを介して使用される場合)、ID プロパティが最初に入力され、循環オブジェクト参照の解決が可能になります。その後、コンストラクターによってまだ設定されていないすべての非一時的なプロパティがエンティティインスタンスに設定されます。そのために、次のアルゴリズムを使用します。

  1. プロパティが不変であるが with …  メソッドを公開している場合(以下を参照)、with …  メソッドを使用して、新しいプロパティ値を持つ新しいエンティティインスタンスを作成します。

  2. プロパティアクセス(つまり、getter および setter を介したアクセス)が定義されている場合、setter メソッドを呼び出しています。

  3. プロパティが変更可能な場合、フィールドを直接設定します。

  4. プロパティが不変の場合、永続化操作(オブジェクト作成を参照)で使用されるコンストラクターを使用して、インスタンスのコピーを作成します。

  5. デフォルトでは、フィールド値を直接設定します。

プロパティ設定の詳細

オブジェクト構築の最適化と同様に、Spring Data ランタイム生成のアクセサークラスを使用して、エンティティインスタンスと対話します。

class Person {

  private final Long id;
  private String firstname;
  private @AccessType(Type.PROPERTY) String lastname;

  Person() {
    this.id = null;
  }

  Person(Long id, String firstname, String lastname) {
    // Field assignments
  }

  Person withId(Long id) {
    return new Person(id, this.firstname, this.lastame);
  }

  void setLastname(String lastname) {
    this.lastname = lastname;
  }
}
例 1: 生成されたプロパティアクセサー
class PersonPropertyAccessor implements PersistentPropertyAccessor {

  private static final MethodHandle firstname;              (2)

  private Person person;                                    (1)

  public void setProperty(PersistentProperty property, Object value) {

    String name = property.getName();

    if ("firstname".equals(name)) {
      firstname.invoke(person, (String) value);             (2)
    } else if ("id".equals(name)) {
      this.person = person.withId((Long) value);            (3)
    } else if ("lastname".equals(name)) {
      this.person.setLastname((String) value);              (4)
    }
  }
}
1PropertyAccessor は、基礎となるオブジェクトの可変インスタンスを保持します。これは、そうでなければ不変のプロパティの変更を可能にするためです。
2 デフォルトでは、Spring Data はフィールドアクセスを使用してプロパティ値を読み書きします。private フィールドの可視性ルールに従って、MethodHandles はフィールドとの対話に使用されます。
3 クラスは、識別子の設定に使用される withId(…) メソッドを公開します。インスタンスがデータストアに挿入され、識別子が生成されたとき。withId(…) を呼び出すと、新しい Person オブジェクトが作成されます。後続のすべての変更は、新しいインスタンスで行われ、前のインスタンスは変更されません。
4property-access を使用すると、MethodHandles を使用せずに直接メソッドを呼び出すことができます。

これにより、反射よりも約 25% パフォーマンスが向上します。ドメインクラスがこのような最適化の対象となるには、一連の制約に従う必要があります。

  • 型は、デフォルトまたは java パッケージに存在してはなりません。

  • 型とそのコンストラクターは public でなければなりません

  • 内部クラスである型は static でなければなりません。

  • 使用される Java ランタイムは、元の ClassLoader でクラスを宣言できるようにする必要があります。Java 9 以降には特定の制限があります。

デフォルトでは、Spring Data は生成されたプロパティアクセサーを使用しようとし、制限が検出された場合はリフレクションベースのものにフォールバックします。

次のエンティティを見てみましょう。

例 2: サンプルエンティティ
class Person {

  private final @Id Long id;                                                (1)
  private final String firstname, lastname;                                 (2)
  private final LocalDate birthday;
  private final int age;                                                    (3)

  private String comment;                                                   (4)
  private @AccessType(Type.PROPERTY) String remarks;                        (5)

  static Person of(String firstname, String lastname, LocalDate birthday) { (6)

    return new Person(null, firstname, lastname, birthday,
      Period.between(birthday, LocalDate.now()).getYears());
  }

  Person(Long id, String firstname, String lastname, LocalDate birthday, int age) { (6)

    this.id = id;
    this.firstname = firstname;
    this.lastname = lastname;
    this.birthday = birthday;
    this.age = age;
  }

  Person withId(Long id) {                                                  (1)
    return new Person(id, this.firstname, this.lastname, this.birthday, this.age);
  }

  void setRemarks(String remarks) {                                         (5)
    this.remarks = remarks;
  }
}
1identifier プロパティは final ですが、コンストラクターで null に設定されます。クラスは、識別子の設定に使用される withId(…) メソッドを公開します。インスタンスがデータストアに挿入され、識別子が生成されたとき。元の Person インスタンスは、新しいインスタンスが作成されるときに変更されません。通常、ストア管理される他のプロパティにも同じパターンが適用されますが、永続化操作のために変更する必要がある場合があります。永続化コンストラクター(6 を参照)は事実上コピーコンストラクターであり、プロパティの設定は新しい識別子値が適用された新しいインスタンスの作成に変換されるため、wither メソッドはオプションです。
2firstname および lastname プロパティは、getter を介して潜在的に公開される通常の不変のプロパティです。
3age プロパティは不変ですが、birthday プロパティから派生しています。示されている設計では、Spring Data は宣言された唯一のコンストラクターを使用するため、データベース値はデフォルト設定よりも優先されます。計算が優先されることを意図している場合でも、このコンストラクターがパラメーターとして age を受け取ることが重要です(無視される可能性があります)。そうしないと、プロパティ生成ステップは age フィールドを設定しようとし、不変で no with …  メソッドが存在します。
4comment プロパティは可変であり、フィールドを直接設定することで入力されます。
5remarks プロパティは可変であり、comment フィールドを直接設定するか、setter メソッドを呼び出して設定します。
6 このクラスは、オブジェクト作成用のファクトリメソッドとコンストラクターを公開します。ここでの核となる考え方は、追加のコンストラクターの代わりにファクトリメソッドを使用して、@PersistenceConstructor によるコンストラクターの明確化の必要性を回避することです。代わりに、プロパティのデフォルト設定はファクトリメソッド内で処理されます。

9.1.3. 一般的な推奨事項

  • 不変オブジェクトにこだわる — 不変オブジェクトは、オブジェクトを具体化するのはコンストラクターのみを呼び出すだけなので、簡単に作成できます。また、これにより、クライアントオブジェクトがオブジェクトの状態を操作できるようにする setter メソッドがドメインオブジェクトに散らばるのを防ぎます。それらが必要な場合は、同じ場所に配置された限られた型でのみ呼び出せるように、パッケージを保護することをお勧めします。コンストラクターのみの実体化は、プロパティの設定よりも最大 30% 高速です。

  • all-args コンストラクターを提供する  — エンティティを不変の値としてモデル化できない、またはしたくない場合でも、オブジェクトのマッピングがプロパティの設定をスキップできるため、エンティティのすべてのプロパティを引数として取るコンストラクターを提供することには価値があります。最適なパフォーマンスのため。

  • @PersistenceConstructor を回避するために、オーバーロードされたコンストラクターの代わりにファクトリメソッドを使用します — 最適なパフォーマンスに必要なすべての引数コンストラクターでは、通常、自動生成識別子などを省略したアプリケーションユースケース固有のコンストラクターを公開します。これらの all-args コンストラクターのバリアントを公開する静的ファクトリメソッド。

  • 生成されたインスタンス生成クラスとプロパティアクセッサクラスを使用できるようにする制約を必ず守ってください。

  • 生成される識別子については、すべての引数の永続化コンストラクター(推奨)または with …  メソッドと組み合わせて final フィールドを使用します

  • Lombok を使用してボイラープレートコードを回避します — 永続化操作は通常、すべての引数を取るコンストラクターを必要とするため、その宣言はフィールド割り当てに対するボイラープレートパラメーターの退屈な繰り返しとなりますが、Lombok の @AllArgsConstructor を使用することで回避することができます。

9.1.4. Kotlin サポート

Spring Data は、Kotlin の仕様を適合させて、オブジェクトの作成と変更を可能にします。

Kotlin オブジェクトの作成

Kotlin クラスはインスタンス化がサポートされており、すべてのクラスはデフォルトで不変であり、可変プロパティを定義するには明示的なプロパティ宣言が必要です。次の data クラス Person を検討してください。

data class Person(val id: String, val name: String)

上記のクラスは、明示的なコンストラクターを持つ典型的なクラスにコンパイルされます。別のコンストラクターを追加してこのクラスをカスタマイズし、@PersistenceConstructor でアノテーションを付けてコンストラクターの設定を示します。

data class Person(var id: String, val name: String) {

    @PersistenceConstructor
    constructor(id: String) : this(id, "unknown")
}

Kotlin は、パラメーターが提供されない場合にデフォルト値を使用できるようにすることで、パラメーターのオプションをサポートしています。Spring Data がパラメーターのデフォルト設定を持つコンストラクターを検出した場合、データストアが値を提供しない(または単に null を返す)場合、Kotlin はパラメーターのデフォルト設定を適用できるため、これらのパラメーターは存在しません。name のパラメーターのデフォルト設定を適用する次のクラスを検討してください。

data class Person(var id: String, val name: String = "unknown")

name パラメーターが結果の一部ではないか、その値が null であるたびに、name は unknown にデフォルト設定されます。

Kotlin データクラスのプロパティ設定

Kotlin では、すべてのクラスはデフォルトで不変であり、可変プロパティを定義するには明示的なプロパティ宣言が必要です。次の data クラス Person を検討してください。

data class Person(val id: String, val name: String)

このクラスは事実上不変です。Kotlin が既存のオブジェクトからすべてのプロパティ値をコピーしてメソッドに引数として提供されたプロパティ値を適用する新しいオブジェクトインスタンスを作成する copy(…) メソッドを生成するときに、新しいインスタンスを作成できます。

9.2. エンティティマッピング

Spring Data for Apache Geode は、リージョンに格納されているエンティティのマッピングをサポートします。マッピングメタデータは、アプリケーションドメインクラスのアノテーションを使用して定義されます。以下に例を示します。

例 3: ドメインクラスを Apache Geode 領域にマッピングする
@Region("People")
public class Person {

  @Id Long id;

  String firstname;
  String lastname;

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

  …
}

@Region アノテーションは、Person クラスのインスタンスが格納されるリージョンをカスタマイズするために使用できます。@Id アノテーションは、キャッシュリージョンのキーとして使用するプロパティをアノテーションし、リージョンエントリを識別するために使用できます。@PersistenceConstructor アノテーションは、パラメーターを受け取り、エンティティの構築に使用するコンストラクターとして明示的にマークすることで、複数のコンストラクターを区別できます。コンストラクターが存在しない、または 1 つしかないアプリケーションドメインクラスでは、アノテーションを省略できます。

最上位レベルのリージョンにエンティティを格納するだけでなく、次の例に示すように、サブリージョンにもエンティティを格納することができます。

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

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

<*-region> 要素の id または name 属性を使用して、Apache Geode XML 名前空間の Spring Data で定義されている Apache Geode 領域の完全なパスを必ず使用してください。

9.2.1. 領域型別のエンティティマッピング

@Region アノテーションに加えて、Apache Geode の Spring Data は、型固有の領域マッピングアノテーション @ClientRegion、@LocalRegion、@PartitionRegion、@ReplicateRegion も認識します。

関数には、これらのアノテーションは SDG マッピングインフラストラクチャにおける汎用 @Region アノテーションと全く同じように扱われます。しかし、これらの追加のマッピングアノテーションは、Spring Data において Apache Geode のアノテーション設定モデルに役立ちます。Spring の @Configuration アノテーション付きクラスにおける @EnableEntityDefinedRegions 設定アノテーションと組み合わせることで、アプリケーションがクライアントかピアかを問わず、ローカルキャッシュにリージョンを生成することが可能になります。

これらのアノテーションを使用すると、アプリケーションエンティティクラスをどの型のリージョンにマッピングするかをより具体的に指定できるだけでなく、リージョンのデータ管理ポリシー (たとえば、パーティション (シャーディングとも呼ばれます) とデータの複製) にも影響を及ぼします。

これらの型固有のリージョンマッピングアノテーションを SDG アノテーション構成モデルで使用すると、構成でこれらのリージョンを明示的に定義する必要がなくなります。

9.3. リポジトリマッピング

エンティティクラスの @Region アノテーションを使用してエンティティが格納されるリージョンを指定する代わりに、エンティティの Repository インターフェースに @Region アノテーションを指定することもできます。詳細については、Spring Data for Apache Geode Repositories を参照してください。

しかし、Person レコードを複数の Apache Geode 領域(たとえば、People と Customers)に格納したいとします。その場合、対応する Repository インターフェース拡張を以下のように定義できます。

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

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

次に、各リポジトリを個別に使用して、次の例に示すように、エンティティを複数の Apache Geode リージョンに保存できます。

@Service
class CustomerService {

  CustomerRepository customerRepo;

  PersonRepository personRepo;

  Customer update(Customer customer) {
    customerRepo.save(customer);
    personRepo.save(customer);
    return customer;
  }

update サービスメソッドを、ローカルキャッシュトランザクションまたはグローバルトランザクションのいずれかとして、Spring 管理トランザクションにラップすることもできます。

9.4. MappingPdxSerializer

Apache Geode 用の Spring Data は、Spring Data マッピングメタデータを使用してエンティティの直列化をカスタマイズする、MappingPdxSerializer と呼ばれるカスタム PdxSerializer [Apache] (英語) 実装を提供します。

シリアライザでは、Spring Data EntityInstantiator 抽象化を使用してエンティティのインスタンス化をカスタマイズすることもできます。デフォルトでは、シリアライザは ReflectionEntityInstantiator を使用します。これは、マッピングされたエンティティの永続化コンストラクターを使用します。永続化コンストラクターは、デフォルトコンストラクター、単独で宣言されたコンストラクター、明示的に @PersistenceConstructor アノテーションが付与されたコンストラクターのいずれかです。

コンストラクターパラメーターに引数を提供するために、シリアライザーは、次の例に示すように、提供された PdxReader [Apache] (英語) から、Spring の @Value アノテーションを使用して明示的に識別された、名前付きコンストラクターパラメーターを持つフィールドを読み取ります。

例 4: エンティティコンストラクターパラメーターで @Value を使用する
public class Person {

  public Person(@Value("#root.thing") String firstName, @Value("bean") String lastName) {
    …
  }
}

このようにアノテーションされたエンティティクラスでは、PdxReader から読み取られた "thing" フィールドがコンストラクターパラメーター firstname の引数値として渡されます。lastName の値は、"Bean" という名前の Spring Bean です。

EntityInstantiators が提供するカスタムインスタンス化ロジックと戦略に加えて、MappingPdxSerializer は Apache Geode 独自の ReflectionBasedAutoSerializer [Apache] (英語) をはるかに超える機能も提供します。

Apache Geode の ReflectionBasedAutoSerializer は、エンティティを設定するために Java リフレクションを便利に使用し、シリアライザーによって処理 (直列化およびデ直列化) される型を識別するために正規表現を使用しますが、MappingPdxSerializer とは異なり、次の操作は実行できません。

  • エンティティフィールドまたはプロパティの名前と型ごとにカスタム PdxSerializer オブジェクトを登録します。

  • ID プロパティを便利に識別します。

  • 読み取り専用プロパティを自動的に処理します。

  • 一時的なプロパティを自動的に処理します。

  • null および型安全な方法で、より堅牢な型 フィルタリングを可能にします (たとえば、正規表現を使用した型の表現のみに限定されません)。

ここで、MappingPdxSerializer の各機能についてもう少し詳しく見ていきましょう。

9.4.1. カスタム PdxSerializer 登録

MappingPdxSerializer を使用すると、エンティティのフィールドまたはプロパティの名前と型に基づいてカスタム PdxSerializers を登録できます。

たとえば、次のように User をモデル化するエンティティ型を定義したとします。

package example.app.security.auth.model;

public class User {

  private String name;

  private Password password;

  ...
}

ユーザー名の値を直列化するために特別なロジックはおそらく必要ありませんが、一方でパスワードを直列化する場合は、フィールドまたはプロパティの機密性を処理するための追加のロジックが必要になる場合があります。

TLS だけでなく、クライアントとサーバー間でネットワーク経由で値を送信する際にパスワードを保護したい場合、ソルト付きハッシュのみを保存したいとします。MappingPdxSerializer を使用する場合、ユーザーのパスワードを処理するカスタム PdxSerializer を以下のように登録できます。

例 5: POJO フィールド / プロパティ型によるカスタム PdxSerializers の登録
Map<?, PdxSerializer> customPdxSerializers = new HashMap<>();

customPdxSerializers.put(Password.class, new SaltedHashPasswordPdxSerializer());

mappingPdxSerializer.setCustomPdxSerializers(customPdxSerializers);

アプリケーション定義の SaltedHashPasswordPdxSerializer インスタンスを Password アプリケーションドメインモデル型に登録した後、MappingPdxSerializer はカスタム PdxSerializer を参照して、含まれているオブジェクト (たとえば、User) に関係なく、すべての Password オブジェクトを直列化および逆直列化します。

しかし、User オブジェクトのみで Passwords の直列化をカスタマイズしたいとします。そのためには、次の例のように、Class’s フィールドまたはプロパティの完全修飾名を指定して、User 型にカスタム PdxSerializer を登録します。

例 6: POJO フィールド / プロパティ名によるカスタム PdxSerializers の登録
Map<?, PdxSerializer> customPdxSerializers = new HashMap<>();

customPdxSerializers.put("example.app.security.auth.model.User.password", new SaltedHashPasswordPdxSerializer());

mappingPdxSerializer.setCustomPdxSerializers(customPdxSerializers);

完全修飾フィールドまたはプロパティ名 (つまり example.app.security.auth.model.User.password) がカスタム PdxSerializer 登録キーとして使用されていることに注意してください。

より論理的なコードスニペット、たとえば User.class.getName().concat(".password"); を使って登録キーを作成することもできます。先ほど示した例よりも、こちらの方が推奨されます。前の例では、登録のセマンティクスを可能な限り明確にしようとしました。

9.4.2. ID プロパティのマッピング

Apache Geode の ReflectionBasedAutoSerializer と同様に、SDG の MappingPdxSerializer もエンティティの識別子を特定できます。ただし、MappingPdxSerializer は Spring Data のマッピングメタデータを使用し、具体的には Spring Data の @Id (Javadoc) アノテーションを使用して識別子として指定されたエンティティプロパティを見つけることでこれを実現します。あるいは、@Id で明示的にアノテーションが付けられていない "id" という名前のフィールドまたはプロパティも、エンティティの識別子として指定されます。

例:

class Customer {

  @Id
  Long id;

  ...
}

この場合、直列化中に PdxSerializer.toData(..) メソッドが呼び出されると、PdxWriter.markIdentifierField(:String) [Apache] (英語) を使用して PDX 型メタデータ内の Customer id フィールドが識別子フィールドとしてマークされます。

9.4.3. 読み取り専用プロパティのマッピング

エンティティが読み取り専用プロパティを定義するとどうなるでしょうか?

まず、「読み取り専用」プロパティとは何かを理解することが重要です。JavaBeans [Oracle] (英語) 仕様に従って POJO を定義する場合(Spring のように)、次のように読み取り専用プロパティを持つ POJO を定義することができます。

package example;

class ApplicationDomainType {

  private AnotherType readOnly;

  public AnotherType getReadOnly() [
    this.readOnly;
  }

  ...
}

readOnly プロパティは、setter メソッドを提供しないため、読み取り専用です。getter メソッドのみを提供します。この場合、readOnly プロパティ(readOnly および DomainType フィールドと混同しないように)は読み取り専用とみなされます。

その結果、特に PDX 直列化されたバイトに値が存在する場合、PdxSerializer.fromData(:Class<ApplicationDomainType>, :PdxReader) メソッドで ApplicationDomainType のインスタンスに値を設定する際に、MappingPdxSerializer はこのプロパティに値を設定しようとはしません。

これは、エンティティ型のビューや射影を返す場合で、書き込み可能な状態のみを設定したい場合に役立ちます。エンティティのビューや射影は、認証やその他の条件に基づいている場合があります。つまり、この機能はアプリケーションのユースケースや要件に合わせて適切に活用できます。フィールドやプロパティを常に書き込み可能にしたい場合は、setter メソッドを定義するだけで済みます。

9.4.4. 一時プロパティのマッピング

同様に、エンティティが transient プロパティを定義した場合、何が起こるでしょうか?

エンティティを直列化する際に、エンティティの transient フィールドまたはプロパティが PDX に直列化されないことを期待するでしょう。実際、Apache Geode の ReflectionBasedAutoSerializer とは異なり、Java リフレクションを介してオブジェクトからアクセス可能なすべてが直列化されるのではなく、まさにそのように動作します。

MappingPdxSerializer は、Java 独自の transient キーワード (クラスインスタンスフィールドの場合) を使用するか、フィールドまたはプロパティに @Transient (Javadoc) 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 (標準 Javadoc) インターフェースと API を使用して型一致条件を表現します。

正規表現を使いたい場合は、Java の正規表現サポート (標準 Javadoc) を使用して Predicate を実装できます。

Java の Predicate インターフェースの優れた点は、and(:Predicate) (標準 Javadoc) 、or(:Predicate) (標準 Javadoc) 、negate() (標準 Javadoc) などの便利で適切な API メソッドを使用して Predicates を構成できることです。

以下の例は、Predicate API の動作を示しています。

Predicate<Class<?>> customerTypes =
  type -> Customer.class.getPackage().getName().startsWith(type.getName()); // Include all types in the same package as `Customer`

Predicate includedTypes = customerTypes
  .or(type -> User.class.isAssignble(type)); // Additionally, include User sub-types (e.g. Admin, Guest, etc)

mappingPdxSerializer.setIncludeTypeFilters(includedTypes);

mappingPdxSerializer.setExcludeTypeFilters(
  type -> !Reference.class.getPackage(type.getPackage()); // Exclude Reference types
Predicate に渡される Class オブジェクトは、null ではないことが保証されています。

SDG の MappingPdxSerializer は、クラス型のフィルターの包含と除外の両方をサポートしています。

除外型フィルタリング

デフォルトでは、SDG の MappingPdxSerializer は、以下のパッケージから型をフィルタリングまたは除外する事前定義済みの Predicates を登録します。

  • java.*

  • com.gemstone.gemfire.*

  • org.apache.geode.*

  • org.springframework.*

さらに、MappingPdxSerializer は PdxSerializer.toData(:Object, :PdxWriter) メソッドを呼び出す際に null オブジェクトをフィルタリングし、PdxSerializer.fromData(:Class<?>, :PdxReader) メソッドを呼び出す際に null クラス型をフィルタリングします。

前述のように、Predicate を定義して MappingPdxSerializer に追加するだけで、他のクラス型や型パッケージ全体に対する除外を簡単に追加できます。

MappingPdxSerializer.setExcludeTypeFilters(:Predicate<Class<?>>) 方式は加算方式であり、Predicate.and(:Predicate<Class<?>>) 方式を使用して、アプリケーション定義の型フィルターと、上記で示した既存の事前定義型フィルター Predicates を合成します。

ただし、除外型フィルターによって暗黙的に除外されるクラス型(たとえば、java.security Principal)を含めたい場合はどうすればよいでしょうか? 包含型フィルタリングを参照してください。

包含型フィルタリング

クラス型を明示的に含めたい場合、またはアプリケーションに必要なクラス型を暗黙的に除外するクラス型フィルターをオーバーライドする場合(たとえば、MappingPdxSerializer の java.* パッケージ除外型フィルターでデフォルトで除外される java.security.Principal など)、適切な 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 Repositories

Spring Data for Apache Geode は、Spring Data リポジトリ抽象化を使用してエンティティを Apache Geode に容易に永続化したり、クエリを実行したりするためのサポートを提供します。リポジトリプログラミングモデルの概要については、こちらを参照してください。

10.1. Spring XML 設定

Spring Data リポジトリをブートストラップするには、次の例に示すように、Spring Data for Apache Geode データ名前空間の <repositories/> 要素を使用します。

例 7: XML で Apache Geode リポジトリ用の Spring Data ブートストラップ
<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 (Javadoc) によってサポートされるそれらのインターフェースのリポジトリインスタンスを作成します。

アプリケーションのドメインクラスが構成済みのリージョンに正しくマッピングされていない限り、ブートストラッププロセスは失敗します。

10.2. Spring Java ベースの構成

あるいは、多くの開発者は Spring の Java ベースのコンテナー構成を使用することを優先します。

この方法を用いると、次の例に示すように、SDG @EnableGemfireRepositories アノテーションを使用して Spring Data リポジトリをブートストラップできます。

例 8: @EnableGemfireRepositories を使用して Apache Geode リポジトリ用の Spring Data をブートストラップする
@SpringBootApplication
@EnableGemfireRepositories(basePackages = "com.example.acme.repository")
class SpringDataApplication {
  ...
}

basePackages 属性を使用する代わりに、型安全な basePackageClasses 属性を使用することをお勧めします。basePackageClasses 属性を使用すると、アプリケーションリポジトリのインターフェース型を 1 つだけ指定することで、すべてのアプリケーションリポジトリクラスを含むパッケージを指定できます。各パッケージに、この属性で参照されるアプリケーションリポジトリの場所を識別するためだけの、特別な何もしないマーカークラスまたはインターフェースを作成することを検討してください。

basePackages and basePackageClasses 属性に加え、Spring の @ComponentScan (Javadoc) アノテーションと同様に、@EnableGemfireRepositories アノテーションは Spring の ComponentScan.Filter (Javadoc) 型に基づいて、包含フィルターと除外フィルターを提供します。filterType 属性を使用すると、アプリケーションのリポジトリ型に特定のアノテーションが付与されているか、特定のクラス型を継承しているかなど、さまざまな側面でフィルタリングできます。詳細については、FilterType Javadoc を参照してください。

@EnableGemfireRepositories アノテーションでは、namedQueriesLocation 属性を使用して、Java Properties ファイルに存在する名前付き OQL クエリの場所を指定することもできます。プロパティ名はリポジトリクエリメソッドの名前と一致させる必要があり、プロパティ値はリポジトリクエリメソッドが呼び出されたときに実行する OQL クエリです。

Apache Geode でカスタムリポジトリ実装が必要となる例の 1 つは、結合を実行する場合です。SDG リポジトリでは結合はサポートされていません。Apache Geode は「分散」結合をサポートしていないため、Apache Geode PARTITION リージョンを使用する場合は、結合は同一場所に配置された PARTITION リージョンに対して実行する必要があります。さらに、Equi-Join OQL クエリは Apache Geode 関数内で実行する必要があります。Apache Geode Equi-Join クエリの詳細については、こちら (英語) を参照してください。

SDG リポジトリのインフラストラクチャ拡張機能のその他の多くの側面もカスタマイズ可能です。すべての設定の詳細については、@EnableGemfireRepositories (Javadoc) の Javadoc を参照してください。

10.3. OQL クエリの実行

Spring Data for Apache Geode リポジトリを使用すると、次の例に示すように、管理対象エンティティがマッピングされるリージョンに対して Apache Geode OQL クエリを簡単に実行するためのクエリメソッドを定義できます。

例 9: サンプルリポジトリ
@Region("People")
public class Person { … }
public interface PersonRepository extends CrudRepository<Person, Long> {

  Person findByEmailAddress(String emailAddress);

  Collection<Person> findByFirstname(String firstname);

  @Query("SELECT * FROM /People p WHERE p.firstname = $1")
  Collection<Person> findByFirstnameAnnotated(String firstname);

  @Query("SELECT * FROM /People p WHERE p.firstname IN SET $1")
  Collection<Person> findByFirstnamesAnnotated(Collection<String> firstnames);
}

前述の例で示した最初のクエリメソッドでは、次の OQL クエリが生成されます: SELECT x FROM /People x WHERE x.emailAddress = $1. 2 番目のクエリメソッドは、最初のクエリメソッドが単一の結果を返すことを想定しているのに対し、見つかったすべてのエンティティを返す点を除いて、同様の動作をします。

サポートされているキーワードだけでは OQL クエリを宣言および表現するのに不十分な場合、またはメソッド名が冗長になりすぎる場合は、3 番目と 4 番目のメソッドに示すように、クエリメソッドに @Query をアノテーションとして追加できます。

以下の表は、クエリメソッドで使用できるサポートされているキーワードの簡単な例を示しています。

表 4: クエリメソッドでサポートされるキーワード
キーワード サンプル 論理的な結果

GreaterThan

findByAgeGreaterThan(int age)

x.age > $1

GreaterThanEqual

findByAgeGreaterThanEqual(int age)

x.age >= $1

LessThan

findByAgeLessThan(int age)

x.age < $1

LessThanEqual

findByAgeLessThanEqual(int age)

x.age ⇐ $1

IsNotNull, NotNull

findByFirstnameNotNull()

x.firstname =! NULL

IsNull, Null

findByFirstnameNull()

x.firstname = NULL

In

findByFirstnameIn(Collection<String> x)

x.firstname IN SET $1

NotIn

findByFirstnameNotIn(Collection<String> x)

x.firstname NOT IN SET $1

IgnoreCase

findByFirstnameIgnoreCase(String firstName)

x.firstname.equalsIgnoreCase($1)

(キーワードなし)

findByFirstname(String name)

x.firstname = $1

Like

findByFirstnameLike(String name)

x.firstname LIKE $1

Not

findByFirstnameNot(String name)

x.firstname != $1

IsTrue, True

findByActiveIsTrue()

x.active = true

IsFalse, False

findByActiveIsFalse()

x.active = false

10.4. アノテーションを使用した OQL クエリ拡張

Apache Geode の OQL(オブジェクトクエリ言語)など、多くのクエリ言語には、Spring Data Commons のリポジトリインフラストラクチャで直接サポートされていない拡張機能があります。

Spring Data Commons のリポジトリインフラストラクチャのゴールの一つは、現在アプリケーション開発で利用されている幅広いデータストアに対応し、移植性を維持するための最小公倍数として機能することです。技術的には、これは開発者が既存のアプリケーション固有のリポジトリインターフェースを再利用することで、Spring Data Commons がサポートする複数の異なるデータストアにアプリケーション内でアクセスできることを意味します。これは便利で強力な抽象化です。

Apache Geode の OQL クエリ言語拡張機能をサポートし、異なるデータストア間での移植性を維持するために、Apache Geode 向けの Spring Data は Java アノテーションを使用して OQL クエリ拡張機能のサポートを追加します。これらのアノテーションは、同様のクエリ言語機能を持たない他の Spring Data リポジトリ実装(Spring Data JPA、Spring Data、Redis など)では無視されます。

たとえば、多くのデータストアは、Apache Geode の OQL キーワード IMPORT を実装していない可能性が高いです。IMPORT をクエリメソッドシグネチャー (具体的にはメソッド名) の一部としてではなく、アノテーション (つまり @Import) として実装しても、クエリメソッド名を評価して別のデータストア言語に適したクエリを構築する際の解析インフラストラクチャに干渉しません。

現在、Spring Data が Apache Geode 向けにサポートしている Apache Geode OQL クエリ言語拡張機能は以下のとおりです。

表 5: リポジトリクエリメソッド用の Apache Geode OQL 拡張機能がサポートされています
キーワード アノテーション 説明 引数

HINT [Apache] (英語)

@Hint

OQL クエリインデックスのヒント

String[] (e.g. @Hint({ "IdIdx", "TxDateIdx" }))

IMPORT [Apache] (英語)

@Import

アプリケーション固有の型を明記してください。

String (e.g. @Import("org.example.app.domain.Type"))

LIMIT [Apache] (英語)

@Limit

返されるクエリ結果セットを制限します。

Integer (e.g. @Limit(10); default is Integer.MAX_VALUE)

TRACE [Apache] (英語)

@Trace

OQL クエリ固有のデバッグを有効にします。

NA

たとえば、Customers アプリケーションドメインクラスとそれに対応する Apache Geode リージョン、CustomerRepository、姓で Customers を検索するクエリメソッドがあるとします。以下はその例です。

例 10: 顧客サンプルリポジトリ
package ...;

import org.springframework.data.annotation.Id;
import org.springframework.data.gemfire.mapping.annotation.Region;
...

@Region("Customers")
public class Customer ... {

  @Id
  private Long id;

  ...
}
package ...;

import org.springframework.data.gemfire.repository.GemfireRepository;
...

public interface CustomerRepository extends GemfireRepository<Customer, Long> {

  @Trace
  @Limit(10)
  @Hint("LastNameIdx")
  @Import("org.example.app.domain.Customer")
  List<Customer> findByLastName(String lastName);

  ...
}

上記の例を実行すると、次の OQL クエリが生成されます。

<TRACE> <HINT 'LastNameIdx'> IMPORT org.example.app.domain.Customer; SELECT * FROM /Customers x WHERE x.lastName = $1 LIMIT 10

Apache Geode のリポジトリ拡張機能用の Spring Data は、OQL アノテーション拡張機能が @Query アノテーションと組み合わせて使用される場合に、競合する宣言を作成しないように注意しています。

別の例として、CustomerRepository に以下のような、@Query のアノテーション付きクエリメソッドが定義されているとします。

例 11: CustomerRepository
public interface CustomerRepository extends GemfireRepository<Customer, Long> {

  @Trace
  @Limit(10)
  @Hint("CustomerIdx")
  @Import("org.example.app.domain.Customer")
  @Query("<TRACE> <HINT 'ReputationIdx'> SELECT DISTINCT * FROM /Customers c WHERE c.reputation > $1 ORDER BY c.reputation DESC LIMIT 5")
  List<Customer> findDistinctCustomersByReputationGreaterThanOrderByReputationDesc(Integer reputation);

}

上記のクエリ方法を実行すると、以下の OQL クエリが生成されます。

IMPORT org.example.app.domain.Customer; <TRACE> <HINT 'ReputationIdx'> SELECT DISTINCT * FROM /Customers x WHERE x.reputation > $1 ORDER BY c.reputation DESC LIMIT 5

@Limit(10) アノテーションは、生クエリで明示的に定義された LIMIT を上書きしません。また、@Hint("CustomerIdx") アノテーションは、生クエリで明示的に定義された HINT を上書きしません。最後に、@Trace アノテーションは冗長であり、追加の効果はありません。

ReputationIdx インデックスは、評判値が同じ顧客が多数存在する可能性があるため、おそらく最も適切なインデックスとは言えません。顧客が同程度の評価を与えると、インデックスの有効性が低下します。インデックスやその他の最適化は慎重に選択してください。不適切なインデックスや選択ミスのあるインデックスは、インデックスの維持管理にかかるオーバーヘッドのために、パフォーマンスに逆効果をもたらす可能性があります。ReputationIdx は、この例の目的のためだけに使用されました。

10.5. クエリ後処理

Spring Data リポジトリ抽象化のおかげで、データストア固有のクエリ(OQL など)を定義するためのクエリメソッドの規約は簡単かつ便利です。しかし、リポジトリクエリメソッドから生成されたクエリをインスペクションしたり、場合によっては変更したりしたい場合もあります。

2.0.x 以降、Apache Geode 向けの Spring Data には o.s.d.gemfire.repository.query.QueryPostProcessor 関数インターフェースが含まれています。このインターフェースは、おおまかに以下のように定義されます。

例 12: QueryPostProcessor
package org.springframework.data.gemfire.repository.query;

import org.springframework.core.Ordered;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.QueryMethod;
import ...;

@FunctionalInterface
interface QueryPostProcessor<T extends Repository, QUERY> extends Ordered {

  QUERY postProcess(QueryMethod queryMethod, QUERY query, Object... arguments);

}

java.util.function.Function.andThen(:Function) (標準 Javadoc) や java.util.function.Function.compose(:Function) (標準 Javadoc) と同様に、QueryPostProcessor のインスタンスを構成できる追加のデフォルトメソッドが用意されています。

さらに、QueryPostProcessor インターフェースは org.springframework.core.Ordered (Javadoc) インターフェースを実装しており、これは複数の QueryPostProcessors が Spring コンテナー内で宣言および登録され、生成されたクエリメソッドクエリのグループに対する処理パイプラインを作成するために使用される場合に便利です。

最後に、QueryPostProcessor は、それぞれ型パラメーター T および QUERY に対応する型引数を受け入れます。型 T は、Spring Data Commons マーカーインターフェース org.springframework.data.repository.Repository (Javadoc) を継承します。これについては、このセクションの後半で詳しく説明します。Apache Geode の場合の Spring Data のすべての QUERY 型パラメーター引数は、型 java.lang.String です。

この QueryPostProcessor インターフェースは Spring Data Commons に移植される可能性があるため、クエリを QUERY 型として定義すると便利です。そのため、JPA、MongoDB、Redis など、さまざまなデータストアによるすべての形式のクエリを処理する必要があります。

このインターフェースを実装すると、メソッドが呼び出されたときに、アプリケーション Repository インターフェースメソッドから生成されたクエリを含むコールバックを受け取ることができます。

例: すべてのアプリケーションリポジトリインターフェース定義からのすべてのクエリをログに記録したい場合、次の QueryPostProcessor 実装を使用することでそれが可能です。

例 13: LoggingQueryPostProcessor
package example;

import ...;

class LoggingQueryPostProcessor implements QueryPostProcessor<Repository, String> {

  private Logger logger = Logger.getLogger("someLoggerName");

  @Override
  public String postProcess(QueryMethod queryMethod, String query, Object... arguments) {

      String message = String.format("Executing query [%s] with arguments [%s]", query, Arrays.toString(arguments));

      this.logger.info(message);
  }
}

LoggingQueryPostProcessor は Spring Data org.springframework.data.repository.Repository マーカーインターフェースに型されているため、アプリケーションリポジトリインターフェースクエリメソッドによって生成されたすべてのクエリをログに記録します。

次の例に示すように、このログ記録の範囲を、CustomerRepository などの特定の種類のアプリケーションリポジトリインターフェースからのクエリのみに限定することができます。

例 14: CustomerRepository
interface CustomerRepository extends CrudRepository<Customer, Long> {

  Customer findByAccountNumber(String accountNumber);

  List<Customer> findByLastNameLike(String lastName);

}

そうすれば、次のように LoggingQueryPostProcessor を CustomerRepository に具体的に入力できたはずです。

例 15: CustomerLoggingQueryPostProcessor
class LoggingQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> { .. }

その結果、findByAccountNumber などの CustomerRepository インターフェースで定義されたクエリのみがログに記録されます。

リポジトリクエリメソッドで定義された特定のクエリに対して、QueryPostProcessor を作成する必要がある場合があります。たとえば、CustomerRepository.findByLastNameLike(:String) クエリメソッドから生成される OQL クエリで、Customers を firstName で昇順に並べ替え、結果を 5 つだけ返すように制限したいとします。そのためには、次の例に示すように、カスタム QueryPostProcessor を定義できます。

例 16: OrderedLimitedCustomerByLastNameQueryPostProcessor
class OrderedLimitedCustomerByLastNameQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> {

  private final int limit;

  public OrderedLimitedCustomerByLastNameQueryPostProcessor(int limit) {
    this.limit = limit;
  }

  @Override
  public String postProcess(QueryMethod queryMethod, String query, Object... arguments) {

    return "findByLastNameLike".equals(queryMethod.getName())
      ? query.trim()
          .replace("SELECT", "SELECT DISTINCT")
          .concat(" ORDER BY firstName ASC")
          .concat(String.format(" LIMIT %d", this.limit))
      : query;
  }
}

上記の例は機能しますが、Spring Data が Apache Geode 向けに提供している Spring Data リポジトリ規約を使用することで、同じ効果を得ることができます。たとえば、同じクエリを次のように定義できます。

例 17: CustomerRepository は規約を使用しています
interface CustomerRepository extends CrudRepository<Customer, Long> {

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

}

ただし、アプリケーションの CustomerRepository インターフェース定義を制御できない場合は、QueryPostProcessor (つまり OrderedLimitedCustomerByLastNameQueryPostProcessor)が便利です。

LoggingQueryPostProcessor が、Spring ApplicationContext で宣言および登録されている可能性のある、アプリケーション定義の別の QueryPostProcessors の後に必ず来るようにするには、次の例に示すように、o.s.core.Ordered.getOrder() メソッドをオーバーライドして order プロパティを設定できます。

例 18: order プロパティの定義
class LoggingQueryPostProcessor implements QueryPostProcessor<Repository, String> {

  @Override
  int getOrder() {
    return 1;
  }
}

class CustomerQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> {

  @Override
  int getOrder() {
    return 0;
  }
}

これにより、LoggingQueryPostProcessor がクエリをログに記録する前に、他の QueryPostProcessors によって適用された後処理の効果が必ず確認できるようになります。

Spring ApplicationContext では、必要な数の QueryPostProcessors を定義し、任意の順序で、すべてのアプリケーションリポジトリインターフェースまたは特定のアプリケーションリポジトリインターフェースに適用できます。また、postProcess(..) メソッドコールバックに提供される引数を使用することで、必要なだけ詳細な設定を行うことができます。

11. 関数実行のアノテーションサポート

Apache Geode 用の Spring Data には、Apache Geode 関数実行 [Apache] (英語) との連携を簡素化するためのアノテーションサポートが含まれています。

内部的には、Apache Geode API は、Apache Geode サーバーにデプロイされる Apache Geode および関数 [Apache] (英語) を実装および登録するためのクラスを提供し、これらのクラスは他のピアメンバーアプリケーションから、またはキャッシュクライアントからリモートで呼び出すことができます。

関数は、クラスタ内の複数の Apache Geode サーバーに分散して並列実行され、マップリデュースパターンを使用して結果を集約し、呼び出し元に返送されます。関数は、単一のサーバーまたはリージョンで実行するように指定することもできます。Apache Geode API は、リージョン、メンバー (グループ内)、サーバーなど、さまざまな事前定義されたスコープを使用してターゲットを指定した関数の リモート実行をサポートしています。リモート関数の実装と実行は、他の RPC プロトコルと同様に、定型コードが必要です。

Spring のコアバリュープロポジションに忠実に、Apache Geode 向けの Spring Data は、リモート関数の実行メカニズムを隠蔽し、コアとなる POJO プログラミングとビジネスロジックに集中できるようにすることを目的としています。この目的のために、Apache Geode 向けの Spring Data では、POJO クラスの public メソッドを Apache Geode 関数として宣言的に登録するためのアノテーションと、アノテーション付きインターフェースを使用して登録済みの関数を呼び出す(リモートから呼び出すことも含む)機能が導入されています。

11.1. 実装と実行

対処すべき関心事は、導入と実行という 2 つに分けられます。

まず、関数実装(サーバー側)があり、これは呼び出し引数にアクセスするために FunctionContext [Apache] (英語) と、結果を送信するために ResultsSender [Apache] (英語) と、その他の実行コンテキスト情報とやり取りする必要があります。関数実装は通常、キャッシュとリージョンにアクセスし、一意の ID で FunctionService [Apache] (英語) に登録されます。

関数を呼び出すキャッシュクライアントアプリケーションは、実装に依存しません。関数を呼び出すには、アプリケーションは関数 ID、呼び出し引数、関数のターゲット(リージョン、サーバー、サーバー群、メンバー、メンバー群のスコープを定義する)を指定して Execution [Apache] (英語) をインスタンス化します。関数が結果を生成する場合、呼び出し元は ResultCollector [Apache] (英語) を使用して実行結果を集約して取得します。場合によっては、カスタムの ResultCollector 実装が必要となり、Execution に登録されることがあります。

ここで使用されている「クライアント」と「サーバー」は、関数実行の文脈におけるものであり、Apache Geode のクライアント / サーバー構成におけるクライアントとサーバーとは異なる意味を持つ場合があります。ClientCache インスタンスを使用するアプリケーションがクラスタ内の 1 つ以上の Apache Geode サーバー上で関数を呼び出すことは一般的ですが、ピアツーピア(P2P)構成で関数を実行することも可能です。この場合、アプリケーションはピア Cache インスタンスをホストするクラスタのメンバーとなります。ピアメンバーキャッシュアプリケーションは、クラスタのピアメンバーであることのすべての制約を受けることに注意してください。

11.2. 関数の実装

Apache Geode API を使用すると、FunctionContext はクライアントの呼び出し引数と、結果をクライアントに返す ResultSender 実装を含む実行時呼び出しコンテキストを提供します。さらに、関数がリージョンで実行される場合、FunctionContext は実際には RegionFunctionContext のインスタンスであり、関数が呼び出されたターゲットリージョン、Execution に関連付けられたフィルター (特定のキーのセット) など、追加情報を提供します。リージョンが PARTITION リージョンの場合、関数は PartitionRegionHelper を使用してローカルデータセットを抽出する必要があります。

Spring を使用すると、シンプルな POJO を作成し、Spring コンテナーを使用して POJO のパブリックメソッドを 1 つ以上関数にバインドできます。関数として使用することを意図した POJO メソッドのシグネチャーは、一般的にクライアントの実行引数に準拠する必要があります。ただし、リージョン実行の場合は、リージョンデータも提供できます (リージョンが PARTITION リージョンの場合は、データはローカルパーティションに保持されていると考えられます)。

さらに、関数は適用されたフィルター(存在する場合)を必要とする場合があります。これは、クライアントとサーバーが呼び出し引数に関する契約を共有しているものの、メソッドシグネチャーには FunctionContext によって提供される値を渡すための追加パラメーターが含まれる可能性があることを提案しています。クライアントとサーバーが共通のインターフェースを共有することも考えられますが、これは厳密には必須ではありません。唯一の制約は、メソッドシグネチャーに、追加パラメーターが解決された後に関数が呼び出されたときと同じ呼び出し引数のシーケンスが含まれていることです。

例: クライアントが呼び出し引数として String と int を提供するとします。これらは、次の例に示すように、配列として FunctionContext に提供されます。

Object[] args = new Object[] { "test", 123 };

Spring コンテナーは、以下のようなメソッドシグネチャーにバインドできる必要があります(現時点では戻り値の型は無視します)。

public Object method1(String s1, int i2) { ... }
public Object method2(Map<?, ?> data, String s1, int i2) { ... }
public Object method3(String s1, Map<?, ?> data, int i2) { ... }
public Object method4(String s1, Map<?, ?> data, Set<?> filter, int i2) { ... }
public void method4(String s1, Set<?> filter, int i2, Region<?,?> data) { ... }
public void method5(String s1, ResultSender rs, int i2) { ... }
public void method6(FunctionContest context) { ... }

一般的なルールとして、追加の引数(リージョンデータとフィルター)が解決された後は、残りの引数は、順序と型において、期待される Function メソッドのパラメーターと完全に一致する必要があります。メソッドの戻り値の型は、void または直列化可能な型(java.io.Serializable、DataSerializable、PdxSerializable として)である必要があります。後者は、呼び出し側の引数にも適用されます。

リージョンデータは通常、単体テストを容易にするために Map として定義する必要がありますが、必要に応じてリージョン型にすることもできます。前述の例に示すように、結果をクライアントに返す方法を制御する必要がある場合は、FunctionContext 自体または ResultSender を渡すことも有効です。

11.2.1. 関数実装のアノテーション

次の例は、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 (Javadoc) でラップすることができます。Spring は、@GemfireFunction アノテーションが付けられた各メソッドに対してラッパーインスタンスを作成します。各ラッパーインスタンスは、対応するメソッドを呼び出すために同じターゲットオブジェクトインスタンスを共有します。

POJO Function クラスが Spring Bean であるという事実は、他にも利点をもたらす可能性があります。キャッシュやリージョンなどの Apache Geode コンポーネントと ApplicationContext を共有しているため、必要に応じてこれらのコンポーネントをクラスに注入することができます。

Spring はラッパークラスを作成し、Apache Geode の FunctionService に関数を登録します。各関数を登録するために使用される関数 ID は一意である必要があります。慣例として、デフォルトでは単純な(修飾されていない)メソッド名が使用されます。名前は、@GemfireFunction アノテーションの id 属性を使用して明示的に定義できます。

@GemfireFunction アノテーションは、Apache Geode の Function [Apache] (英語) インターフェースで定義されたプロパティに対応する、HA および optimizedForWrite という他の構成属性も提供します。

POJO Function メソッドの戻り値の型が void の場合、hasResult 属性は自動的に false に設定されます。それ以外の場合、メソッドが値を返すと、hasResult 属性は true に設定されます。void メソッドの戻り値の型であっても、前述の functionWithContext メソッドで示されているように、GemfireFunction アノテーションの hasResult 属性を true に設定することで、この規則を上書きできます。おそらく、呼び出し元に結果を送信するには、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 は、指定されている場合は Target リージョン内の有効なキーになります。

PojoFunctionWrapper は Apache Geode の Function インターフェースを実装し、メソッドパラメーターをバインドし、execute() メソッド内でターゲットメソッドを呼び出します。また、ResultSender を使用してメソッドの戻り値を呼び出し元に返します。

11.2.2. 結果のバッチ処理

戻り値の型が配列または Collection の場合、結果の返され方について考慮する必要があります。デフォルトでは、PojoFunctionWrapper は配列全体または Collection を一度に返します。配列または Collection の要素数が非常に多い場合、パフォーマンスが低下する可能性があります。ペイロードをより小さく扱いやすいチャンクに分割するには、前述の function2 で示したように、batchSize 属性を設定できます。

ResultSender をより細かく制御する必要がある場合、特にメソッド自体が Collection を作成するためにメモリを過剰に使用する場合は、ResultSender を渡すか、FunctionContext を介してアクセスし、メソッド内で直接使用して呼び出し元に結果を返すことができます。

11.2.3. アノテーション処理の有効化

Spring 規格に従い、@GemfireFunction アノテーションについてはアノテーション処理を明示的に有効化する必要があります。以下の例は、XML を使用してアノテーション処理を有効化する例です。

<gfe:annotation-driven/>

次の例では、Java 構成クラスにアノテーションを付けることで、アノテーション処理を有効にします。

@Configuration
@EnableGemfireFunctions
class ApplicationConfiguration { ... }

11.3. 関数の実行

リモート関数を呼び出すプロセスは、関数の ID、呼び出し引数、実行ターゲット (onRegion、onServers、onServer、onMember または onMembers)、および (オプションで) フィルターセットを提供する必要があります。Apache Geode に Spring Data を使用すると、アノテーションでサポートされているインターフェースを定義するだけで済みます。Spring はインターフェースの動的プロキシを作成し、FunctionService を使用して Execution を作成し、Execution を呼び出し、(必要に応じて) 結果を定義された戻り値型に強制します。この手法は、Apache Geode のリポジトリ拡張機能の Spring Data の動作方法と似ています。構成と概念の一部は馴染みのあるものです。

一般的に、1 つのインターフェース定義は複数の関数実行に対応し、それぞれの関数実行はインターフェースで定義された各メソッドに対応します。

11.3.1. 関数実行のためのアノテーション

クライアント側での関数実行をサポートするために、次の SDG 関数アノテーションが提供されています: @OnRegion、@OnServer、@OnServers、@OnMember、@OnMembers。これらのアノテーションは、Apache Geode の FunctionService [Apache] (英語) クラスによって提供される Execution 実装に対応しています。

各アノテーションは、適切な属性を公開します。これらのアノテーションは、オプションの resultCollector 属性も提供します。この属性の値は、実行に使用する ResultCollector [Apache] (英語) インターフェースを実装する Spring Bean の名前です。

プロキシインターフェースは、宣言されたすべてのメソッドを同じ実行構成にバインドします。単一メソッドのインターフェースが一般的であると想定されますが、インターフェース内のすべてのメソッドは同じプロキシインスタンスによってサポートされるため、すべて同じ構成を共有します。

以下にいくつかの例を示します。

@OnRegion(region="SomeRegion", resultCollector="myCollector")
public interface FunctionExecution {

    @FunctionId("function1")
    String doIt(String s1, int i2);

    String getString(Object arg1, @Filter Set<Object> keys);

}

デフォルトでは、関数 ID は単純な(修飾されていない)メソッド名です。@FunctionId アノテーションを使用すると、この呼び出しを別の関数 ID にバインドできます。

11.3.2. アノテーション処理の有効化

クライアント側では、Spring のクラスパスコンポーネントスキャン機能を使用して、アノテーション付きインターフェースを検出します。XML で関数実行アノテーション処理を有効にするには、XML 設定に次の要素を挿入してください。

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

function-executions 要素は、gfe-data XML 名前空間に用意されています。base-package 属性は、クラスパス全体をスキャンしないようにするために必要です。追加のフィルターは、Spring リファレンスドキュメント (英語) に記載されているとおりに指定できます。

必要に応じて、Java 構成クラスに以下のようにアノテーションを付けることができます。

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

11.4. プログラムによる関数の実行

前のセクションで定義した関数実行アノテーション付きインターフェースを使用して、関数を呼び出すアプリケーション Bean にインターフェースを自動的にワイヤリングします。

@Component
public class MyApplication {

    @Autowired
    FunctionExecution functionExecution;

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

あるいは、関数実行テンプレートを直接使用することもできます。次の例では、GemfireOnRegionFunctionTemplate が onRegion 関数 Execution を作成します。

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

内部的には、関数 Executions は常に List を返します。executeAndExtract は、結果を含むシングルトン List を想定し、その値をリクエストされた型に強制変換しようとします。また、List をそのまま返す execute メソッドもあります。最初のパラメーターは関数 ID です。フィルター引数は省略可能です。残りの引数は可変引数 List です。

11.5. PDX による関数実行

Spring Data を Apache Geode の関数アノテーションサポートと Apache Geode の PDX 直列化 [Apache] (英語) と組み合わせて使用する場合、いくつか留意すべき事項があります。

このセクションですでに説明したように、また例として、通常は、Apache Geode 関数アノテーション (Javadoc) に対して Spring Data アノテーションが付けられた POJO クラスを使用して、Apache Geode 関数を定義する必要があります。以下に示します。

public class OrderFunctions {

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

}
Integer 型の count パラメーターは任意であり、Order クラスと OrderSource 列挙型の分離も同様に任意です。これらは結合した方が論理的かもしれない。しかし、これらの引数は PDX 環境における関数実行の問題点を実証するために、このように設定されています。

Order クラスと OrderSource 列挙型は、以下のように定義できます。

public class Order ... {

  private Long orderNumber;
  private LocalDateTime orderDateTime;
  private Customer customer;
  private List<Item> items

  ...
}


public enum OrderSource {
  ONLINE,
  PHONE,
  POINT_OF_SALE
  ...
}

もちろん、次のようにして、関数 Execution インターフェースを定義して、「プロセス」Apache Geode サーバー関数を呼び出すことができます。

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

明らかに、この process(..) Order 関数は、クライアント側から ClientCache インスタンス (つまり <gfe:client-cache/>) を使用して呼び出されています。これは、関数の引数も直列化可能である必要があることを意味します。クラスタ内のピア間でピアツーピアのメンバー関数 (@OnMember(s) など) を呼び出す場合も同様です。distribution のどの形式であっても、クライアントとサーバー (またはピア) 間で送信されるデータは直列化されている必要があります。

Apache Geode をシリアライゼーションに PDX を使用するように構成している場合(たとえば、Java シリアライゼーションの代わりに)、Apache Geode サーバーの構成で pdx-read-serialized 属性を true に設定することもできます。手順は次のとおりです。

<gfe:cache pdx-read-serialized="true"/>

あるいは、Apache Geode キャッシュクライアントアプリケーションの場合、次のように pdx-read-serialized 属性を true に設定することもできます。

<gfe:client-cache pdx-read-serialized="true"/>

そうすることで、キャッシュ(つまりリージョン)から読み取られたすべての値、およびクライアントとサーバー(またはピア)間で渡される情報(関数引数を含むがこれに限定されない)が直列化された形式のままになります。

Apache Geode は、Apache Geode の ReflectionBasedAutoSerializer [Apache] (英語) を使用するか、特に (推奨) カスタムの Apache Geode PdxSerializer [Apache] (英語) を使用することで、ユーザーが明示的に構成 (登録) したアプリケーションドメインオブジェクト型のみを直列化します。Apache Geode のリポジトリ拡張機能に Spring Data を使用している場合は、Apache Geode の MappingPdxSerializer (Javadoc) に Spring Data を使用することも検討してください。Spring Data は、エンティティのマッピングメタデータを使用して、PDX インスタンスに直列化されるアプリケーションドメインオブジェクトのデータを決定します。

しかし、あまり知られていないのは、Java 列挙型が java.io.Serializable を実装しているにもかかわらず、明示的に構成されているかどうか (つまり、ReflectionBasedAutoSerializer に登録されているか、正規表現パターンと classes パラメーターを使用しているか、「カスタム」 Apache Geode PdxSerializer によって処理されているか) に関係なく、Apache Geode が Java Enum 型を自動的に処理するということです。

Apache Geode 関数 (Apache Geode 関数アノテーション付き POJO クラス用の Spring Data を含む) が登録されている Apache Geode サーバーで pdx-read-serialized を true に設定すると、関数 Execution を呼び出すときに予期しない動作が発生する可能性があります。

関数を呼び出す際に、以下の引数を渡すことができます。

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

しかし、サーバー上の Apache Geode 関数は以下を取得します。

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

Order と OrderSource は PDX インスタンス [Apache] (英語) として関数に渡されました。これもすべて、pdx-read-serialized が true に設定されているためです。これは、Apache Geode サーバーが複数の異なるクライアント(たとえば、Java クライアントとネイティブクライアントの組み合わせ、C/C++、C# など)とやり取りする場合に必要となる可能性があります。

これは、Apache Geode の厳密に型付けされた関数アノテーション付き POJO クラスのメソッドシグネチャーに関する Spring Data の仕様に反するものであり、そこでは PDX 直列化されたインスタンスではなく、アプリケーションドメインオブジェクト型が期待されるのが妥当です。

そのため、Apache Geode 向けの Spring Data には、PDX 型のメソッド引数を、Function メソッドのシグネチャー(パラメーター型)で定義された目的のアプリケーションドメインオブジェクト型に自動的に変換する、強化された Function サポートが含まれています。

ただし、これには、Apache Geode 関数アノテーション付き POJO の Spring Data が登録され使用される 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 [Apache] (英語) を使用することもできます。もちろん、可能な限りカスタムの PdxSerializer を使用して、直列化戦略をより細かく制御することをお勧めします。

最後に、Spring Data から Apache Geode への変換では、関数引数を汎用的に扱う場合、または Apache Geode の PDX 型のいずれかとして扱う場合、関数引数を変換しないように注意しています。以下にその例を示します。

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

Spring Data から Apache Geode への変換は、対応するアプリケーションドメイン型がクラスパス上に存在し、かつ Function アノテーションが付与された POJO メソッドがそれを期待している場合に限り、PDX 型のデータを対応するアプリケーションドメイン型に変換します。

カスタムで構成されたアプリケーション固有の Apache Geode PdxSerializers の良い例、およびメソッドシグネチャーに基づく適切な POJO 関数パラメーター型の処理については、Apache Geode の ClientCacheFunctionExecutionWithPdxIntegrationTest [GitHub] (英語) クラスに関する Spring Data を参照してください。

12. Apache Lucene 統合

Apache Geode (英語) は Apache Lucene (英語) と連携し、Lucene クエリを使用して Apache Geode に保存されたデータのインデックス作成と検索を可能にします。検索ベースのクエリには、クエリ結果をページングする機能も含まれています。

さらに、Spring Data for Apache Geode では、Spring Data Commons の射影インフラストラクチャに基づいたクエリ射影のサポートが追加されました。この機能により、アプリケーションのニーズに応じて、クエリ結果を第一級アプリケーションドメイン型に射影することが可能になります。

Lucene の検索ベースのクエリを実行する前に、Lucene Index を作成する必要があります。LuceneIndex は、Spring(Apache Geode のデータ)XML 設定で次のように作成できます。

<gfe:lucene-index id="IndexOne" fields="fieldOne, fieldTwo" region-path="/Example"/>

さらに、Apache Lucene ではフィールドごとにアナライザー [Apache] (英語) を指定することができ、次の例に示すように構成できます。

<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"/>。

Apache Geode の LuceneIndexFactoryBean API および SDG の XML 名前空間用の Spring Data では、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>

あるいは、次の例に示すように、@Configuration クラス内で Spring Java 設定ファイル内に LuceneIndex を宣言または定義することもできます。

@Bean(name = "Books")
@DependsOn("bookTitleIndex")
PartitionedRegionFactoryBean<Long, Book> booksRegion(GemFireCache gemfireCache) {

    PartitionedRegionFactoryBean<Long, Book> peopleRegion =
        new PartitionedRegionFactoryBean<>();

    peopleRegion.setCache(gemfireCache);
    peopleRegion.setClose(false);
    peopleRegion.setPersistent(false);

    return peopleRegion;
}

@Bean
LuceneIndexFactoryBean bookTitleIndex(GemFireCache gemFireCache,
        LuceneSerializer luceneSerializer) {

    LuceneIndexFactoryBean luceneIndex = new LuceneIndexFactoryBean();

    luceneIndex.setCache(gemFireCache);
    luceneIndex.setFields("title");
    luceneIndex.setLuceneSerializer(luceneSerializer);
    luceneIndex.setRegionPath("/Books");

    return luceneIndex;
}

@Bean
CustomLuceneSerializer myLuceneSerialier() {
    return new CustomeLuceneSerializer();
}

Apache Geode と Apache Lucene の統合およびサポートには、いくつかの制限事項があります。

まず、LuceneIndex は Apache Geode PARTITION リージョン上にのみ作成できます。

第二に、すべての LuceneIndexes は、LuceneIndex が適用されるリージョンより前に作成されていなければなりません。

Spring コンテナーで定義された宣言済みの LuceneIndexes が、それらが適用されるリージョンより前に作成されるようにするため、SDG には org.springframework.data.gemfire.config.support.LuceneIndexRegionBeanFactoryPostProcessor が含まれています。この Spring BeanFactoryPostProcessor (Javadoc) は、<bean class="org.springframework.data.gemfire.config.support.LuceneIndexRegionBeanFactoryPostProcessor"/> を使用して XML 設定に登録できます。o.s.d.g.config.support.LuceneIndexRegionBeanFactoryPostProcessor は、SDG XML 設定を使用する場合にのみ使用できます。Spring の BeanFactoryPostProcessors の詳細については、こちらを参照してください。

これらの Apache Geode の制限は将来のリリースでは適用されなくなる可能性があるため、SDG LuceneIndexFactoryBean API はリージョンパスだけでなく、リージョン自体への参照も直接受け取るようになっています。

これは、アプリケーションのライフサイクルの後半で、要件に応じて既存のリージョンにデータを含む LuceneIndex を定義する場合に特に適しています。SDG は可能な限り厳密に型指定されたオブジェクトを使用するよう努めていますが、現時点では、LuceneIndex を適用するリージョンを指定するには regionPath プロパティを使用する必要があります。

さらに、前述の例では、Spring の @DependsOn アノテーションが Books リージョン Bean 定義に存在することに注目してください。これにより、Books リージョン Bean から bookTitleIndex LuceneIndex Bean 定義への依存関係が作成され、LuceneIndex が適用されるリージョンより前に作成されることが保証されます。

LuceneIndex を取得できたため、クエリなどの Lucene ベースのデータアクセス操作を実行できます。

12.1. Lucene テンプレートデータアクセサー

Spring Data for Apache Geode は、アプリケーションがどの程度低いレベルのデータ処理に対応できるかに応じて、Lucene データアクセス操作のための 2 つの主要なテンプレートを提供します。

LuceneOperations インターフェースは、以下のインターフェース定義で定義されている Apache Geode ルセン型 [Apache] (英語) を使用してクエリ操作を定義します。

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 [Apache] (英語) インターフェースが提供する操作と一致します。しかし、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 射影インフラストラクチャを使用して、指定された射影型のインスタンスにクエリ結果を適用します。

さらに、このテンプレートは、ページ分割された 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 射影インフラストラクチャの唯一の制約は、射影型がインターフェースでなければならないという点です。ただし、提供されている SDC 射影インフラストラクチャを継承し、CGLIB [GitHub] (英語) を使用してプロキシクラスを射影対象エンティティとして生成するカスタム ProjectionFactory (Javadoc) を提供することは可能です。

setProjectionFactory(:ProjectionFactory) を使用すると、Lucene テンプレートにカスタム ProjectionFactory を設定できます。

12.2. アノテーション設定のサポート

最後に、Apache Geode 用の Spring Data は、LuceneIndexes のアノテーション構成をサポートします。

最終的には、SDG Lucene のサポートが Apache Geode のリポジトリインフラストラクチャ拡張機能に組み込まれ、OQL のサポートが現在行っているのとほぼ同じように、Lucene クエリをアプリケーション 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 ベースのアプリケーションは、Apache Geode の機能に Spring Data を使用することで Apache Geode をブートストラップします。Apache Geode の XML 名前空間に Spring Data を使用する <gfe:cache/> 要素を指定することで、単一の組み込み Apache Geode ピアである Cache インスタンスが作成され、アプリケーションと同じ JVM プロセス内でデフォルト設定で初期化されます。

ただし、場合によっては(IT 部門の要件として)、Apache Geode を Gfsh [Apache] (英語) などを使用して、提供されている Apache Geode ツールスイートで完全に管理および運用する必要があることがあります。Gfsh を使用することで、Apache Geode は Spring ApplicationContext をブートストラップします(逆ではありません)。Spring Boot を使用するアプリケーションサーバーや Java メインクラスの代わりに、Apache Geode がブートストラップを行い、アプリケーションをホストします。

Apache Geode はアプリケーションサーバーではありません。さらに、Apache Geode のキャッシュ構成に関しては、この方法には制限があります。

13.1. Gfsh で開始された Spring コンテキストを Apache Geode を使用してブートストラップする

Gfsh を使用して Apache Geode サーバーを起動する際に、Apache Geode 内の Spring ApplicationContext をブートストラップするには、Apache Geode の初期化 [Apache] (英語) 機能を使用する必要があります。初期化ブロックでは、Apache Geode によってキャッシュが初期化された後に起動されるアプリケーションコールバックを宣言できます。

初期化子は、Apache Geode のネイティブ cache.xml の最小限のスニペットを使用して、初期化子 [Apache] (英語) 要素内で宣言されます。Spring ApplicationContext をブートストラップするには、cache.xml ファイルが必要です。これは、コンポーネントスキャン (たとえば <context:component-scan base-packages="…​"/>) で構成された Spring ApplicationContext をブートストラップするために、Spring XML 設定の最小限のスニペットが必要なのとほぼ同じです。

幸いなことに、そのような初期化子はフレームワークによってすでに便利に提供されています。SpringContextBootstrappingInitializer (Javadoc) です。

以下の例は、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 クラスと同様の規則に従います。ContextLoaderListener クラスは、Web アプリケーション内で Spring ApplicationContext をブートストラップするために使用され、ApplicationContext 構成ファイルは contextConfigLocations サーブレットコンテキストパラメーターで指定されます。

さらに、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 ファイル(前述のとおり)を Gfsh で Apache Geode サーバーを起動する際のコマンドラインオプションとして指定すると、コマンドラインは次のようになります。

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 には、SDG XML 名前空間のすべての要素を含む、有効な Spring 構成メタデータであれば何でも指定できます。この方法の唯一の制限は、SDG XML 名前空間を使用して Apache Geode キャッシュを構成できないことです。つまり、<gfe:cache/> 要素の属性(cache-xml-location、properties-ref、critical-heap-percentage、pdx-serializer-ref、lock-lease など)は指定できません。これらの属性が使用されている場合、無視されます。

その理由は、初期化処理が呼び出される前に、Apache Geode 自体がすでにキャッシュを作成および初期化しているためです。結果として、キャッシュはすでに存在しており、「シングルトン」であるため、再初期化したり、構成を拡張したりすることはできません。

13.2. Apache Geode コンポーネントのレイジーワイヤリング

Spring Data は、オートワイヤーとアノテーションを使用した構成に従って、SDG の WiringDeclarableSupport クラスを使用して Apache Geode が cache.xml で宣言および作成した Apache Geode コンポーネント (CacheListeners、CacheLoaders、CacheWriters など) のオートワイヤーをすでにサポートしています。ただし、これは Spring がブートストラップを実行している場合 (つまり、Spring が Apache Geode をブートストラップする場合) にのみ機能します。

Apache Geode によって Spring ApplicationContext がブートストラップされると、Spring ApplicationContext がまだ存在しないため、これらの Apache Geode アプリケーションコンポーネントは認識されません。Spring ApplicationContext は、Apache Geode が初期化ブロックを呼び出すまで作成されません。初期化ブロックは、他のすべての Apache Geode コンポーネント (キャッシュ、リージョンなど) がすでに作成および初期化された後にのみ実行されます。

この問題を解決するために、新しいクラス LazyWiringDeclarableSupport が導入されました。この新しいクラスは Spring ApplicationContext を認識します。この抽象基底クラスの意図は、実装クラスが、初期化子が呼び出されると最終的に Apache Geode によって作成される Spring コンテナーによって構成されるように登録することです。つまり、これにより、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 は、起動時に Users を Apache Geode REPLICATE リージョンにロードするために、アプリケーションリポジトリ (または、Spring ApplicationContext で定義された JDBC DataSource ) にアクセスする必要がある場合があります。

CAUTION

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.SpringContextBootstrappingInitializerIntegrationTest$UserDataStoreCacheLoader
        </class-name>
      </cache-loader>
    </region-attributes>
  </region>

  <initializer>
    <class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer</class-name>
    <parameter name="basePackages">
      <string>org.springframework.data.gemfire.support.sample</string>
    </parameter>
  </initializer>

</cache>

14. サンプルアプリケーション

サンプルアプリケーションは現在、Spring Apache Geode の例 [GitHub] (英語) リポジトリで管理されています。

Spring Data for Apache Geode プロジェクトには、サンプルアプリケーションも含まれています。"Hello World" という名前のこのサンプルアプリケーションは、Spring アプリケーション内で Apache Geode を設定および使用する方法を示しています。実行時には、データグリッドに対してさまざまなコマンドを実行できるシェルが提供されます。これは、基本的なコンポーネントを習得している開発者、または Spring と Apache Geode の概念を理解している開発者にとって、優れた出発点となります。

サンプルは配布パッケージに同梱されており、Maven ベースです。Maven 対応の IDE(Pleiades All in One (JDK, STS, Lombok 付属) または Eclipse Spring Tool Suite (英語) など)にインポートするか、コマンドラインから実行できます。

14.1. Hello World

"Hello World" サンプルアプリケーションは、Apache Geode 向け Spring Data プロジェクトのコア機能を実証します。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

複数のインスタンスを同時に実行できます。起動後、新しい仮想マシンは既存のリージョンとその情報を自動的に認識します。次の例を参照してください。

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]

ぜひサンプルを試して、必要なだけインスタンスを起動(および停止)し、1 つのインスタンスでさまざまなコマンドを実行して、他のインスタンスがどのように反応するかを確認してみてください。データを保持するには、常に少なくとも 1 つのインスタンスが稼働している必要があります。すべてのインスタンスがシャットダウンされると、グリッドデータは完全に失われます。

14.1.3. Hello World サンプルの説明

"Hello World" サンプルは、構成に Spring XML とアノテーションの両方を使用します。初期ブートストラップ構成は app-context.xml で、cache-context.xml ファイルで定義されたキャッシュ構成を含み、Spring コンポーネント (英語) のクラスパスコンポーネントスキャン (英語) を実行します。

キャッシュ構成では、Apache Geode キャッシュ、領域、説明のためにロガーとして機能する CacheListener を定義します。

主要な Bean は HelloWorld と CommandProcessor で、これらは分散ファブリックとのやり取りに GemfireTemplate を必要とします。どちらのクラスも、依存関係とライフサイクルコールバックを定義するためにアノテーションを使用します。

リソース

このリファレンスドキュメントに加えて、{data-store-product-name} を Spring Framework で使用する方法を学ぶのに役立つリソースが他にも多数あります。これらの追加のサードパーティ製リソースは、このセクションで列挙されています。

付録

Unresolved directive in index.adoc - include::../../../../spring-data-commons/src/main/asciidoc/repository-namespace-reference.adoc[leveloffset=+1] Unresolved directive in index.adoc - include::../../../../spring-data-commons/src/main/asciidoc/repository-populator-namespace-reference.adoc[leveloffset=+1] Unresolved directive in index.adoc - include::../../../../spring-data-commons/src/main/asciidoc/repository-query-keywords-reference.adoc[leveloffset=+1] Unresolved directive in index.adoc - include::../../../../spring-data-commons/src/main/asciidoc/repository-query-return-types-reference.adoc[leveloffset=+1] :leveloffset: +1

付録 A: Spring Data for Apache Geode Schema