42 Contexts and Dependency Injectionの使用
Coherenceは、Coherenceクラスタ・メンバー内のContexts and Dependency Injection (CDI)をサポートします。この機能を使用すると、NamedMap
、NamedCache
、Session
インスタンスなどのCoherence管理対象リソースをCDIマネージドBeanに注入したり、CDI Beanをイベント・インターセプタやキャッシュ・ストアなどのCoherence管理対象リソースに注入したり、CDIオブザーバ・メソッドを使用してCoherenceサーバー側イベントを処理できます。
また、Coherence CDIは、デシリアライズ時に一時オブジェクトの自動注入をサポートします。この機能を使用すると、(ドメイン駆動設計(DDD)命名法を使用する)サービスやリポジトリなどのCDIマネージドBeanを、エントリ・プロセッサやデータ・クラス・インスタンスなどの一時オブジェクトに注入して、ドメイン駆動アプリケーションの実装を大幅に簡素化できます。
この章の内容は次のとおりです。
- CDIの使用
Contexts and Dependency Injection (CDI)をpom.xml
ファイルの依存関係として宣言して、その使用を有効にする必要があります。 - CDI BeanへのCoherenceオブジェクトの注入
一般に、CDIおよび依存関係インジェクションにより、アプリケーション・クラスで必要な依存関係を宣言し、実行時に必要に応じてそれらを提供することが容易になります。この機能により、アプリケーションの開発、テストおよび推論が容易になります。そしてコードは非常にわかりやすくなります。 - Coherence管理対象オブジェクトへのCDI Beanの注入
Coherenceには、多くのサーバー側拡張ポイントがあり、通常はキャッシュ構成ファイルの様々なセクション内で拡張を構成することで、様々な方法でアプリケーションの動作をカスタマイズできます。 - 一時オブジェクトへのCDI Beanの注入
CDIを使用してCoherenceオブジェクトをアプリケーション・クラスに注入し、CDI BeanをCoherence管理対象オブジェクトに注入することで、依存関係インジェクションが役立つ可能性のある多くのユース・ケースをサポートできますが、Coherenceに固有の重要なユース・ケースには対応していません。 - FilterBinding注釈の使用
ビューの作成時またはイベントのサブスクライブ時に、Filters
を使用してビューまたはイベントを変更できます。注入される正確なFilter
実装は、ビューまたはイベント・オブザーバの修飾子によって決定されます。具体的には、それ自体に@FilterBinding
の注釈が付いた修飾子注釈です。 - ExtractorBinding注釈の使用
エクストラクタ・バインディングは、@ExtractorBinding
の注釈が付けられ、com.oracle.coherence.cdi.ExtractorFactory
の実装と組み合せて使用され、CoherenceValueExtractor
インスタンスが生成されます。 - MapEventTransformerBinding注釈の使用
Coherence CDIでは、キャッシュ・エントリまたはマップ・エントリのイベントを監視できるイベント・オブザーバがサポートされています。observer
メソッドにMapEventTransformerBinding
注釈を付けて、オブザーバが監視前に元のイベントにトランスフォーマを適用する必要があることを示すことができます。 - CDIレスポンス・キャッシングの使用
CDIレスポンス・キャッシングを使用すると、Javaメソッドに透過的にキャッシュを適用できます。coherence-CDI
依存関係を追加すると、CDIレスポンス・キャッシングが有効になります。
親トピック: データ・グリッド操作の実行
CDIの使用
Contexts and Dependency Injection (CDI)をpom.xml
ファイルの依存関係として宣言して、その使用を有効にする必要があります。
CDIを依存関係として宣言するには、pom.xml
に次のコンテンツを追加します。
<dependency>
<groupId>${coherence.groupId}</groupId>
<artifactId>coherence-cdi-server</artifactId>
<version>${coherence.version}</version>
</dependency>
必要な依存関係を設定した後、CDIを使用してCoherenceオブジェクトをマネージドCDI Beanに注入できます。
ノート:
CDIを使用する場合、アプリケーション・コードで使用されるすべてのCoherenceリソースを注入する必要があります。アプリケーションでは、Coherenceリソースを直接作成または初期化するCoherence APIをコールしないでください(特に静的CacheFactory
メソッド)。アプリケーション・コードがこれらのCoherence APIをコールすると、CDIフレームワークがCoherence拡張を初期化する前に起動プロセスの初期段階でCoherenceが初期化されることがあります。一般的な症状として、CoherenceはCDIフレームワークから正しい構成を選択せずに起動します。
CDI BeanへのCoherenceオブジェクトの注入
一般に、CDIおよび依存関係インジェクションにより、アプリケーション・クラスで必要な依存関係を宣言し、実行時に必要に応じてそれらを提供することが容易になります。この機能により、アプリケーションの開発、テストおよび推論が容易になります。そしてコードは非常にわかりやすくなります。
Coherence CDIでは、Cluster
、Session
、NamedMap
、NamedCache
、ContinuousQueryCache
、ConfigurableCacheFactory
などのCoherenceオブジェクトに対して同じ操作を実行できます。
この項には次のトピックが含まれます:
NamedMap、NamedCacheおよび関連オブジェクトの注入
NamedMap
のインスタンスをCDI Beanに注入するには、その注入ポイントを定義する必要があります。
import javax.inject.Inject;
@Inject
private NamedMap<Long, Person> people;
前述の例では、注入するマップ名は、注入するフィールドの名前(people
)と同じであると想定されています。そうでない場合は、@Name
修飾子を使用して、明示的に取得するマップの名前を指定できます。
import com.oracle.coherence.cdi.Name;
import javax.inject.Inject;
@Inject
@Name("people")
private NamedMap<Long, Person> m_people;
これは、コンストラクタ注入またはセッター注入を使用している場合にも行う必要があります。
import com.oracle.coherence.cdi.Name;
import javax.inject.Inject;
@Inject
public MyClass(@Name("people") NamedMap<Long, Person> people) {
...
}
@Inject
public void setPeople(@Name("people") NamedMap<Long, Person> people) {
...
}
前述のすべての例では、デフォルトのスコープを使用することを想定していますが、常にそうであるとはかぎりません。たとえば、複数のCoherenceクラスタに接続するExtendクライアントがあるとします。その場合は複数のスコープがあります。
この場合、@SessionName
修飾子を使用して、キャッシュまたはマップの指定に使用される構成済のSession
の名前を指定します。
import com.oracle.coherence.cdi.SessionName;
import javax.inject.Inject;
@Inject
@SessionName("Products")
private NamedCache<Long, Product> products;
@Inject
@SessionName("Customers")
private NamedCache<Long, Customer> customers;
前述の例のいずれかのNamedMap
またはNamedCache
をそれぞれAsyncNamedMap
およびAsyncNamedCache
に置き換えて、これらのAPIの非同期バリアントを注入できます。
import com.oracle.coherence.cdi.SessionName;
import javax.inject.Inject;
@Inject
private AsyncNamedMap<Long, Person> people;
@Inject
@SessionName("Products")
private AsyncNamedCache<Long, Person> Product;
この項には次のトピックが含まれます:
NamedMapまたはNamedCacheビューの注入
NamedMap
またはNamedCache
にView
修飾子を追加して、ビューを注入することもできます。import com.oracle.coherence.cdi.View;
import javax.inject.Inject;
@Inject
@View
private NamedMap<Long, Person> people;
@Inject
@View
private NamedCache<Long, Product> products;
前述の例は同等であり、どちらもビューの構築時にAlwaysFilter
を使用するため、バッキング・マップのすべてのデータをローカル・ビューに取り込みます。ビュー内のデータをサブセットに制限する場合は、カスタムFilterBinding
を実装する(推奨。FilterBinding注釈の使用を参照)か、CohQLを使用してフィルタを指定できる組込みの@WhereFilter
を便宜上使用できます。
import com.oracle.coherence.cdi.Name;
import com.oracle.coherence.cdi.View;
import com.oracle.coherence.cdi.WhereFilter;
import javax.inject.Inject;
@Inject
@View
@WhereFilter("gender = 'MALE'")
@Name("people")
private NamedMap<Long, Person> men;
@Inject
@View
@WhereFilter("gender = 'FEMALE'")
@Name("people")
private NamedMap<Long, Person> women;
ビューでは、ローカルに格納されるデータ量とネットワーク経由で転送されるデータ量の両方を削減するために、サーバー上のエントリ値の変換もサポートされます。たとえば、バッキング・マップに複雑なPerson
オブジェクトがありますが、クライアントUIのドロップダウンに移入するには名前のみが必要です。その場合は、カスタムExtractorBinding
を実装する(推奨。カスタム・エクストラクタ注釈の作成を参照)か、組込みの@PropertyExtractor
を便宜上使用できます。
import com.oracle.coherence.cdi.Name;
import com.oracle.coherence.cdi.View;
import com.oracle.coherence.cdi.PropertyExtractor;
import javax.inject.Inject;
@Inject
@View
@PropertyExtractor("fullName")
@Name("people")
private NamedMap<Long, String> names;
ノート:
この例の値タイプは、指定された@PropertyExtractor
によるサーバー側の変換が原因で、Person
からString
に変更されました。
NamedTopicおよび関連オブジェクトの注入
NamedTopic
のインスタンスをCDI Beanに注入するには、その注入ポイントを定義する必要があります。
import com.tangosol.net.NamedTopic;
import javax.inject.Inject;
@Inject
private NamedTopic<Order> orders;
前述の例では、注入するトピック名は、注入するフィールドの名前(この場合はorders
)と同じであると想定されています。そうでない場合は、@Name
修飾子を使用して、明示的に取得するトピックの名前を指定できます。
import com.oracle.coherence.cdi.Name;
import com.tangosol.net.NamedTopic;
import javax.inject.Inject;
@Inject
@Name("orders")
private NamedTopic<Order> topic;
かわりに'constructor'または'setter input'を使用している場合は、次の操作を実行する必要があります。
import com.oracle.coherence.cdi.Name;
import com.tangosol.net.NamedTopic;
import javax.inject.Inject;
@Inject
public MyClass(@Name("orders") NamedTopic<Order> orders) {
...
}
@Inject
public void setOrdersTopic(@Name("orders") NamedTopic<Order> orders) {
...
}
前述のすべての例では、デフォルトのスコープを使用することを想定していますが、常にそうであるとはかぎりません。たとえば、複数のCoherenceクラスタに接続するExtendクライアントがあるとします。その場合は複数のスコープがあります。
この場合、@SessionName
修飾子を使用して、トピックの指定に使用される構成済のSession
の名前を指定します。
import com.oracle.coherence.cdi.SessionName;
import com.tangosol.net.NamedTopic;
import javax.inject.Inject;
@Inject
@SessionName("Finance")
private NamedTopic<PaymentRequest> payments;
@Inject
@SessionName("Shipping")
private NamedTopic<ShippingRequest> shipments;
前述の例では、CDI BeanにNamedTopic
インスタンスを注入できますが、かわりに特定のトピックにPublisher
またはSubscriber
を注入する方が簡単で便利です。
これは、前述の例のいずれかのNamedTopic<T>
を次のいずれかに置き換えることで簡単に実行できます。
Publisher<T>
:
import com.oracle.coherence.cdi.Name;
import com.oracle.coherence.cdi.SessionName;
import javax.inject.Inject;
@Inject
private Publisher<Order> orders;
@Inject
@Name("orders")
private Publisher<Order> m_orders;
@Inject
@SessionName("Finance")
private Publisher<PaymentRequest> payments;
または
Subscriber<T>
:import com.oracle.coherence.cdi.Name;
import com.oracle.coherence.cdi.SessionName;
import javax.inject.Inject;
@Inject
private Subscriber<Order> orders;
@Inject
@Name("orders")
private Subscriber<Order> m_orders;
@Inject
@SessionName("Finance")
private Subscriber<PaymentRequest> payments;
トピック名(注入ポイント名または@Name
注釈からの明示的な名前に基づく)、スコープおよびメッセージ・タイプなどのトピック・メタデータは、内部で使用され、NamedTopic
を取得し、そこからPublisher
またはSubscriber
を取得します。
また、サブスクライバをサブスクライバ・グループに配置する場合(効果的にトピックをキューに変換する場合)、注入ポイントに@SubscriberGroup
修飾子を追加することで、これを簡単に実行できます。
import com.oracle.coherence.cdi.SubscriberGroup;
import javax.inject.Inject;
@Inject
@SubscriberGroup("orders-queue")
private Subscriber<Order> orders;
親トピック: CDI BeanへのCoherenceオブジェクトの注入
他の注入ポイントのサポート
NamedMap
、NamedCache
、NamedTopic
および関連インスタンスの注入は、Coherence CDIの最も使用される単一機能ですが、これが唯一の機能ではありません。
次の項では、Coherence CDIを使用して注入できるその他のCoherenceアーティファクトについて説明します。
親トピック: CDI BeanへのCoherenceオブジェクトの注入
クラスタおよびOperationalContext注入
アプリケーションの任意の場所にあるCluster
インタフェースのインスタンスが必要な場合は、注入を介して簡単に取得できます。
import com.tangosol.net.Cluster;
import javax.inject.Inject;
@Inject
private Cluster cluster;
OperationalContext
のインスタンスが必要な場合は、同じ操作を実行できます。
import com.tangosol.net.OperationalContext;
import javax.inject.Inject;
@Inject
private OperationalContext ctx;
親トピック: 他の注入ポイントのサポート
名前付きセッション注入
まれに、Session
を直接使用する必要がある場合、Coherence CDIによってそれを簡単に行うことができるようになります。
Coherenceは、CDIサーバーの起動時にデフォルトのSession
を作成します。セッションは、通常のデフォルトのキャッシュ構成ファイルを使用して作成されます。他の名前付きセッションは、タイプSessionConfiguration
のCDI Beanとして構成できます。
たとえば:
import com.oracle.coherence.cdi.SessionInitializer;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class MySession
implements SessionInitializer
{
public String getName()
{
return "Foo";
}
// implement session configuration methods
}
前述のBeanは、Foo
という名前のSession
の構成を作成します。セッションは、CDIサーバーの起動時に作成され、その後、他のBeanに注入されます。SessionConfiguration
を作成するためのより簡単な方法は、SessionIntializer
インタフェースを実装し、クラスに注釈を付けることです。
たとえば:
import com.oracle.coherence.cdi.ConfigUri;
import com.oracle.coherence.cdi.Scope;
import com.oracle.coherence.cdi.SessionInitializer;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
@ApplicationScoped
@Named("Foo")
@Scope("Foo")
@ConfigUri("my-coherence-config.xml")
public class MySession
implements SessionInitializer
{
}
前述の構成では、my-coherence-config.xml
構成ファイルから作成された基礎となるConfigurableCacheFactory
を使用して、Foo
という名前のSession
Beanを作成します。
デフォルトのSession
のインスタンスを取得するには、セッションを使用する必要があるクラスにセッションを注入するだけです。
import com.tangosol.net.Session;
import javax.inject.Inject;
@Inject
private Session session;
特定の名前付きSession
が必要な場合は、@Name
修飾子を使用して修飾し、Session
名を指定できます。
import com.oracle.coherence.cdi.Name;
import javax.inject.Inject;
@Inject
@Name("SessionOne")
private Session sessionOne;
@Inject
@Name("SessionTwo")
private Session sessionTwo;
親トピック: 他の注入ポイントのサポート
シリアライザ注入
ほとんどの場合、シリアライザを直接処理する必要はありませんが、Coherence CDIを使用すると、必要なときに名前付きシリアライザの取得(および新しいシリアライザの登録)が簡単になります。
現在のコンテキスト・クラス・ローダーのデフォルトSerializer
を取得するには、これを注入します。
import com.tangosol.io.Serializer;
import javax.inject.Inject;
@Inject
private Serializer defaultSerializer;
ただし、@Name
修飾子を使用して簡単に実行できる、操作構成で定義されている名前付きシリアライザのいずれかを注入すると役立つ場合があります。
import com.oracle.coherence.cdi.Name;
import javax.inject.Inject;
@Inject
@Name("java")
private Serializer javaSerializer;
@Inject
@Name("pof")
private Serializer pofSerializer;
この例は、操作構成で定義されたシリアライザに加えて、Serializer
インタフェースを実装する名前付きBeanに対してBeanManager
ルックアップも実行します。つまり、次のようなカスタムSerializer
Beanを実装できます。
import com.tangosol.io.Serializer;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
@Named("json")
@ApplicationScoped
public class JsonSerializer implements Serializer {
...
}
カスタムSerializer
BeanはCDIによって自動的に検出および登録されるため、操作構成で定義された名前付きシリアライザのように簡単に注入できます。
import com.oracle.coherence.cdi.Name;
import javax.inject.Inject;
@Inject
@Name("json")
private Serializer jsonSerializer;
親トピック: 他の注入ポイントのサポート
特定のPOF構成のPOFシリアライザ
@Name
修飾子と@ConfigUri
修飾子の両方を使用してPOFシリアライザを注入し、特定のPOF構成ファイルを使用するPOFシリアライザを注入できます。
import com.oracle.coherence.cdi.ConfigUri;
import com.oracle.coherence.cdi.Name;
import javax.inject.Inject;
@Inject
@Name("pof")
@ConfigUri("test-pof-config.xml")
private Serializer pofSerializer;
前述のコードは、test-pof-config.xml
ファイルを構成ファイルとして使用するPOFシリアライザを注入します。
親トピック: 他の注入ポイントのサポート
Coherence管理対象オブジェクトへのCDI Beanの注入
Coherence CDIは、カスタム構成ネームスペース・ハンドラを使用して、名前付きCDI Beanをこれらの拡張ポイントに注入する方法を提供します。
<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xmlns:cdi="class://com.oracle.coherence.cdi.server.CdiNamespaceHandler"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
前述のcdi
ネームスペースのハンドラを宣言した後、通常<class-name>
または<class-factory-name>
要素を使用する任意の場所に<cdi:bean>
要素を指定できます。
<?xml version="1.0"?>
<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xmlns:cdi="class://com.oracle.coherence.cdi.server.CdiNamespaceHandler"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
<interceptors>
<interceptor>
<instance>
<cdi:bean>registrationListener</cdi:bean>
</instance>
</interceptor>
<interceptor>
<instance>
<cdi:bean>activationListener</cdi:bean>
</instance>
</interceptor>
</interceptors>
<caching-scheme-mapping>
<cache-mapping>
<cache-name>*</cache-name>
<scheme-name>distributed-scheme</scheme-name>
<interceptors>
<interceptor>
<instance>
<cdi:bean>cacheListener</cdi:bean>
</instance>
</interceptor>
</interceptors>
</cache-mapping>
</caching-scheme-mapping>
<caching-schemes>
<distributed-scheme>
<scheme-name>distributed-scheme</scheme-name>
<service-name>PartitionedCache</service-name>
<local-storage system-property="coherence.distributed.localstorage">true</local-storage>
<partition-listener>
<cdi:bean>partitionListener</cdi:bean>
</partition-listener>
<member-listener>
<cdi:bean>memberListener</cdi:bean>
</member-listener>
<backing-map-scheme>
<local-scheme/>
</backing-map-scheme>
<autostart>true</autostart>
<interceptors>
<interceptor>
<instance>
<cdi:bean>storageListener</cdi:bean>
</instance>
</interceptor>
</interceptors>
</distributed-scheme>
</caching-schemes>
</cache-config>
<cdi:bean>
要素を使用して、名前付きCDI Bean (明示的な@Named
注釈を持つBean)を注入できます。たとえば、前述のcacheListener
インターセプタBeanは次のようになります。
@ApplicationScoped
@Named("cacheListener")
@EntryEvents(INSERTING)
public class MyCacheListener
implements EventInterceptor<EntryEvent<Long, String>> {
@Override
public void onEvent(EntryEvent<Long, String> e) {
// handle INSERTING event
}
}
また、注入できるのは@ApplicationScoped
Beanのみであることに注意してください。それは共有される可能性があることを意味します。たとえば、例のキャッシュ・マッピング内のキャッシュ名としてワイルドカード*
が使用されているため、cacheListener
の同じインスタンスは、複数のキャッシュからイベントを受け取ります。
イベント自体は、キャッシュ名や発生元のサービスなど、発生したコンテキストの詳細を提供するため、通常はこれで問題ありません。ただし、リスナー・クラス内に存在する可能性がある共有状態は、コンテキスト固有ではなく、複数のスレッドからの同時アクセスに対して安全である必要があることを意味します。後者を保証できない場合は、onEvent
メソッドをsynchronized
として宣言して、一度に1つのスレッドのみが共有状態にアクセスできるようにします。
この項には次のトピックが含まれます:
CDIオブザーバを使用したCoherenceサーバー側イベントの処理
前述の例では、Coherence EventInterceptor
をCDI Beanとして実装し、キャッシュ構成ファイル内の<cdi:bean>
要素を使用して登録できることを示していますが、Coherence CDIでは、標準のCDIイベントおよびオブザーバを使用して同じ目的を達成する、より簡単な方法も提供しています。
たとえば、people
という名前でLong
型のキーとPerson
型の値を使用してNamedMap
によって発生したイベントを監視するには、次のようなCDIオブザーバを定義します。
private void onMapChange(@Observes @MapName("people") EntryEvent<Long, Person> event) {
// handle all events raised by the 'people' map/cache
}
この項には次のトピックが含まれます:
特定のイベント・タイプの監視
@Observes
メソッド(CDIオブザーバを使用したCoherenceサーバー側イベントの処理を参照)は、people
マップのすべてのイベントを受け取りますが、イベント修飾子を使用して受け取るイベントのタイプを制御することもできます。
private void onUpdate(@Observes @Updated @MapName("people") EntryEvent<Long, Person> event) {
// handle UPDATED events raised by the 'people' map/cache
}
private void onChange(@Observes @Inserted @Updated @Removed @MapName("people") EntryEvent<?, ?> event) {
// handle INSERTED, UPDATED and REMOVED events raised by the 'people' map/cache
}
監視対象イベントのフィルタリング
監視されるイベントは、Coherence Filter
を使用してさらに制限できます。フィルタが指定されている場合、イベントはサーバー上でフィルタされ、クライアントには送信されません。フィルタは、それ自体に@FilterBinding
の注釈が付いた修飾子注釈を使用して指定されます。
カスタムFilterBinding
を実装する(推奨。FilterBinding注釈の使用を参照)か、CohQLを使用してフィルタを指定できる組込みの@WhereFilter
を便宜上使用できます。
たとえば、people
マップのすべてのイベント・タイプを受け取り、lastName
プロパティ値がSmith
のPeople
についてのみを受け取るには、組込みの@WhereFilter
注釈を使用できます。
@WhereFilter("lastName = 'Smith'")
private void onMapChange(@Observes @MapName("people") EntryEvent<Long, Person> event) {
// handle all events raised by the 'people' map/cache
}
監視対象イベントの変換
イベント・オブザーバがイベントの完全なキャッシュやマップ値を受け取りたくない場合は、イベントを別の値に変換して監視できます。これは、ExtractorBinding
注釈またはMapEventTransformerBinding
注釈を使用してオブザーバ・メソッドに適用されるMapEventTransformer
を使用して実現されます。イベントの変換はサーバー上で行われるため、完全な古い値と新しい値で元のイベントを受け取る必要がなく、オブザーバをより効率的にすることができます。
この項には次のトピックが含まれます:
ExtractorBinding注釈を使用したイベントの変換
ExtractorBinding
注釈は、Coherence ValueExtractor
を表す注釈です。オブザーバ・メソッドにExtractorBinding
注釈を付けると、結果のValueExtractor
がイベントの値に適用され、抽出されたプロパティのみを含む新しいイベントがオブザーバに返されます。
たとえば、people
という名前のマップからのイベントを監視しているが、姓のみを必要とするイベント・オブザーバは、組込みの@PropertyExtractor
注釈を使用できます。
@PropertyExtractor("lastName")
private void onMapChange(@Observes @MapName("people") EntryEvent<Long, String> event) {
// handle all events raised by the 'people' map/cache
}
前述の例ではタイプEntryEvent<Long, Person>
のイベントを受け取りましたが、このメソッドはタイプEntryEvent<Long, String>
のイベントを受け取ります。これは、プロパティ・エクストラクタが元のイベントのPerson
値に適用されてlastName
プロパティが抽出され、String
値を使用して新しいイベントが作成されるためです。
多数の組込みExtractorBinding
注釈があり、カスタムExtractorBinding
注釈を作成することもできます。カスタム・エクストラクタ注釈の作成を参照してください。
複数のエクストラクタ・バインディング注釈を注入ポイントに追加できます。この場合、複数のプロパティが抽出され、イベントには抽出されたプロパティ値のList
が含まれます。
たとえば、Person
にcity
フィールドを含むAddress
型のaddress
フィールドも含まれている場合、これは@ChainedExtractor
注釈を使用して抽出できます。これを前の例の@PropertyExtractor
と組み合せることで、イベントでlastName
とcity
の両方を監視できます。
@PropertyExtractor("lastName")
@ChainedExtractor({"address", "city"})
private void onMapChange(@Observes @MapName("people") EntryEvent<Long, List<String>> event) {
// handle all events raised by the 'people' map/cache
}
ノート:
複数の抽出値が返されるため、イベントのタイプはEntryEvent<Long, List<String>>
になります。イベント値はList
で、この場合は両方のプロパティのタイプがString
であるため、値はList<String>
です。
親トピック: 監視対象イベントの変換
MapEventTransformerBinding注釈を使用したイベントの変換
イベント値からプロパティを抽出するよりも複雑なイベント変換が必要な場合は、カスタムMapEventTransformer
インスタンスを生成するカスタムMapEventTransformerBinding
を作成し、このインスタンスがオブザーバのイベントに適用されます。カスタム・エクストラクタ注釈の作成を参照してください。
親トピック: 監視対象イベントの変換
特定のサービスおよびスコープでのマップおよびキャッシュのイベントの監視
@MapName
修飾子に加えて、受け取るイベントを制限する方法として@ServiceName
および@ScopeName
修飾子を使用することもできます。
前述の例では、EntryEvents
の処理方法のみを示していますが、他のすべてのサーバー側イベント・タイプにも同じことが当てはまります。
private void onActivated(@Observes @Activated LifecycleEvent event) {
// handle cache factory activation
}
private void onCreatedPeople(@Observes @Created @MapName("people") CacheLifecycleEvent event) {
// handle creation of the 'people' map/cache
}
private void onExecuted(@Observes @Executed @MapName("people") @Processor(Uppercase.class) EntryProcessorEvent event) {
// intercept 'Uppercase` entry processor execution against 'people' map/cache
}
非同期オブザーバの使用
前述のすべての例では、各オブザーバ・メソッドに@Observes
修飾子を指定して、同期オブザーバを使用していました。ただし、Coherence CDIでは非同期CDIオブザーバも完全にサポートされます。前述の例のいずれかで、@Observes
を@ObservesAsync
に置き換えるだけで済みます。
private void onActivated(@ObservesAsync @Activated LifecycleEvent event) {
// handle cache factory activation
}
private void onCreatedPeople(@ObservesAsync @Created @MapName("people") CacheLifecycleEvent event) {
// handle creation of the 'people' map/cache
}
private void onExecuted(@ObservesAsync @Executed @MapName("people") @Processor(Uppercase.class) EntryProcessorEvent event) {
// intercept 'Uppercase` entry processor execution against 'people', map/cache
}
ノート:
Coherenceイベントは、コミット前イベントとコミット後イベントの2つのカテゴリに分類されます。Inserting
、Updating
、Removing
、Executing
など、名前が"ing
"で終わるすべてのイベントは、コミット前イベントです。これらのイベントは、データを変更したり、例外をスローして操作を拒否できますが、そのためには、イベントをトリガーした操作を実行しているものと同じスレッドで実行されるように、イベントを同期する必要があります。
つまり、非同期CDIオブザーバを使用して監視できますが、イベント・ペイロードの一部であるエントリのセットを変更したり、例外をスローしてイベントを拒否する場合は、同期CDIオブザーバを使用する必要があります。
一時オブジェクトへのCDI Beanの注入
CDIを使用してCoherenceオブジェクトをアプリケーション・クラスに注入し、CDI BeanをCoherence管理対象オブジェクトに注入することで、依存関係インジェクションが役立つ可能性のある多くのユース・ケースをサポートできますが、Coherenceに固有の重要なユース・ケースには対応していません。
Coherenceは分散システムであり、シリアライズを使用して、データと処理リクエストの両方をクラスタ・メンバー(またはリモート・クライアント)から別のクラスタ・メンバー(またはリモート・クライアント)に送信し、データをメモリーとディスクの両方に格納します。
エントリ・プロセッサやアグリゲータなどの処理リクエストは、実行するターゲット・クラスタ・メンバーでデシリアライズする必要があります。場合によっては、サービス・ルックアップを回避するために、依存関係インジェクションのメリットが得られることがあります。
同様に、データはシリアライズされたバイナリ形式で格納されますが、エントリ・プロセッサやアグリゲータの実行時など、サーバー側の処理のためにユーザー指定のクラスにデシリアライズする必要がある場合があります。この場合、データ・クラスは、(たとえば、ドメイン駆動設計(DDD)をサポートするために)依存関係インジェクションのメリットが得られることも多くあります。
これらの一時オブジェクトはCDIコンテナによって管理されませんが、Coherence CDIはデシリアライズ時に注入をサポートします。ただし、パフォーマンス上の理由から、com.oracle.coherence.cdi.Injectable
インタフェースを実装して明示的にオプトインする必要があります。
この項には次のトピックが含まれます:
一時クラスを注入可能にする
技術的には真のマーカー・インタフェースではありませんが、Injectable
はすべての意図および目的に対してそのように扱うことができます。デシリアライズ時に注入を開始するには、クラスのimplements
句に追加するだけで済みます。
public class InjectableBean
implements Injectable, Serializable {
@Inject
private Converter<String, String> converter;
private String text;
InjectableBean() {
}
InjectableBean(String text) {
this.text = text;
}
String getConvertedText() {
return converter.convert(text);
}
}
アプリケーションに次のConverter
サービス実装があると仮定すると、デシリアライズ時にInjectableBean
に注入され、getConvertedText
メソッドは大文字に変換されたテキスト・フィールドの値を返します。
@ApplicationScoped
public class ToUpperConverter
implements Converter<String, String> {
@Override
public String convert(String s) {
return s.toUpperCase();
}
}
ノート:
Injectable
クラスに@PostConstruct
コールバック・メソッドがある場合は、注入後にコールされます。ただし、その時点以降はオブジェクトのライフサイクルを制御できないため、@PreDestroy
コールバックは呼び出されません。
この機能は、シリアライズ形式に依存せず、JavaシリアライズとPOFシリアライズの両方(またはその他のカスタム・シリアライザ)、およびCoherenceメンバー(またはリモート・クライアント)でデシリアライズされたオブジェクトに対して機能します。
デシリアライズされた一時オブジェクトは真のCDIマネージドBeanではありませんが、デシリアライズ時にCDIマネージド依存関係をこれらのオブジェクトに注入できると、それらのアプリケーション・コンポーネントで必要となるほとんどの依存関係インジェクション要件を満たす可能性があります。
親トピック: 一時オブジェクトへのCDI Beanの注入
FilterBinding注釈の使用
ビューの作成時またはイベントのサブスクライブ時に、Filters
を使用してビューまたはイベントを変更できます。注入される正確なFilter
実装は、ビューまたはイベント・オブザーバの修飾子によって決定されます。具体的には、それ自体に@FilterBinding
の注釈が付いた修飾子注釈です。
たとえば、基礎となるマップのフィルタされたビューであるビューの注入ポイントがあるが、必要なフィルタが組込みの修飾子で提供されるものよりも複雑である場合、またはカスタム・フィルタ実装である場合は、次のステップを実行します。
- 必要な
Filter
を表すカスタム注釈クラスを作成します。 - カスタム
Filter
のインスタンスを生成するためのファクトリとなるカスタム注釈が付いたcom.oracle.coherence.cdi.FilterFactory
を実装するBeanクラスを作成します。 - ビューの注入ポイントにカスタム注釈を付けます。
この項には次のトピックが含まれます:
カスタム・フィルタ注釈の作成
フィルタ注釈の作成は、@com.oracle.coherence.cdi.FilterBinding
注釈が付いた通常のJava注釈クラスの作成と同じです。
次の例では、Coherence CDI拡張がFilter
を表すことを認識できるように、この新しい注釈にFilterBinding
を付けることが最も重要な部分です。
@Inherited
@FilterBinding
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomFilter {
}
親トピック: FilterBinding注釈の使用
カスタム・フィルタ・ファクトリの作成
カスタム注釈を作成した後、必要なFilter
のインスタンスを生成するFilterFactories
実装を作成できます。
@ApplicationScoped
@CustomFilter
static class CustomFilterSupplier
implements FilterFactory<CustomFilter, Object>
{
@Override
public Filter<Object> create(CustomFilter annotation)
{
return new CustomComplexFilter();
}
}
- CDIで検出できるように、
CustomFilterSupplier
クラスに@ApplicationScoped
という注釈が付けられています。 CustomFilterSupplier
クラスには、Filters
を作成する必要があるときにCoherence CDI拡張で検出できるように、新しいフィルタ・バインディング注釈@CustomFilter
が付けられています。CustomFilterSupplier
は、カスタムFilter
実装を作成するFilterFactories
インタフェースのcreate
メソッドを実装します。
親トピック: FilterBinding注釈の使用
注入ポイントへの注釈付け
カスタム注釈と注釈付きFilterFactories
の両方があるため、Filter
を必要とする注入ポイントに新しい注釈を付けることができます。
@Inject
@View
@CustomFilter
private NamedMap<Long, Person> people;
ビューと同様に、カスタム・フィルタ・バインディング注釈をイベント・オブザーバに使用できます。たとえば、同じカスタムFilter
に一致するイベントのみを受け取るイベント・オブザーバ・メソッドがある場合、メソッドに同じカスタム・フィルタ注釈を付けることができます。
@CustomFilter
private void onPerson(@Observes @MapName("people") EntryEvent<Long, Person> event) {
親トピック: FilterBinding注釈の使用
ExtractorBinding注釈の使用
エクストラクタ・バインディングは、@ExtractorBinding
の注釈が付けられ、com.oracle.coherence.cdi.ExtractorFactory
の実装と組み合せて使用され、Coherence ValueExtractor
インスタンスが生成されます。
Coherence CDIモジュールには多数の組込みのエクストラクタ・バインディング注釈があり、カスタム実装を提供する簡単なプロセスです。
この項には次のトピックが含まれます:
組込みExtractorBinding注釈の使用
次のタイプの組込みExtractorBinding注釈を使用できます。
PropertyExtractor
@PropertyExtractor
注釈を使用して、オブジェクトから名前付きプロパティを抽出するエクストラクタを取得できます。@PropertyExtractor
注釈の値フィールドは、抽出するプロパティの名前です。
たとえば、次の@PropertyExtractor
注釈は、値からlastName
プロパティを抽出するValueExtractor
を表します。
@PropertyExtractor("lastName")
com.tangosol.util.extractor.UniversalExtractor
のインスタンスであるため、この例は次をコールすることと同じです。
new UniversalExtractor("lastName");
@PropertyExtractor
注釈を複数回適用して、値からプロパティのList
を抽出するMultiExtractor
を作成できます。
たとえば、マップ値がfirstName
およびlastName
プロパティを持つPerson
のインスタンスであるpeople
という名前のマップを考えてみます。次のイベント・オブザーバはマップ上のイベントを監視しますが、受け取ったイベントにはイベント・キーと、元のイベントから抽出されたfirstName
およびlastName
を含むList
のみが含まれます。
@PropertyExtractor("firstName")
@PropertyExtractor("lastName")
private void onPerson(@Observes @MapName("people") EntryEvent<Long, List<String>> event) {
ChainedExtractor
@ChainedExtractor
注釈を使用して、プロパティの連鎖を抽出できます。
たとえば、Person
インスタンスには、city
プロパティを含むaddress
プロパティを含めることができます。@ChainedExtractor
は抽出するフィールドの連鎖を取得し、この場合はPerson
からaddress
を抽出し、address
からcity
を抽出します。
@ChainedExtractor("address", "city")
各プロパティ名はUniversalExtractor
の作成に使用され、これらのエクストラクタの配列はcom.tangosol.util.extractor.ChainedExtractor
のインスタンスの作成に使用されます。
前述の例は、次をコールすることと同じです。
UniversalExtractor[] chain = new UniversalExtractor[] {
new UniversalExtractor("address"),
new UniversalExtractor("city")
};
ChainedExtractor extractor = new ChainedExtractor(chain);
PofExtractor
@PofExtractor
注釈を使用して、POFでエンコードされた値からプロパティを抽出できるエクストラクタを生成できます。@PofExtractor
注釈に渡される値は、抽出するプロパティに移動するためのPOFパスです。
たとえば、索引4
でlastName
プロパティを持つPOFを使用してPerson
値をシリアライズした場合は、次に示すように@PofExtractor
注釈を使用できます。
@PofExtractor(index = 4)
前述のコードは、Coherence com.tangosol.util.extractor.PofExtractor
を作成します。これは、次をコールすることと同じです。
com.tangosol.util.extractor.PofExtractor(null, 4);
場合によっては(たとえば、特定のタイプのNumber
を処理する場合)、PofExtractor
は抽出されるタイプを認識している必要があります。この場合、@PofExtractor
注釈でタイプ値を設定できます。
たとえば、POF索引2
でBook
値にLong
型のsales
フィールドがある場合、次の@PofExtractor
注釈を使用してsales
フィールドを抽出できます。
@PofExtractor(index = {2}, type = Long.class)
前述のコードは、Coherence com.tangosol.util.extractor.PofExtractor
を作成します。これは、次をコールすることと同じです。
com.tangosol.util.extractor.PofExtractor(Long.class, 2);
@PofExtractor
注釈のindex
値はint配列であるため、複数のPOF索引値を渡して、抽出するプロパティの連鎖を下に移動できます。たとえば、Person
にPOF索引5
のAddress
が含まれ、Address
にPOF索引3
のcity
プロパティが含まれている場合、次に示すように、@PofExtractor
注釈を使用してPerson
から抽出された市区町村を抽出できます。
@PofExtractor(index = {5, 3})
または、抽出元の値がcom.tangosol.io.pof.schema.annotation.PortableType
で注釈が付けられ、クラスのPOFシリアライズ・コードがCoherence com.tangosol.io.pof.generator.PortableTypeGenerator
を使用して生成されている場合は、path
フィールドを使用して@PofExtractor
注釈にプロパティ名を渡すことができます。
たとえば、POFシリアライズされたPerson
からlastName
フィールドを抽出するには、次に示すように@PofExtractor
注釈を使用できます。
@PofExtractor(path = "lastName")
address
city
の例は次のとおりです。
@PofExtractor(path = {"address", "city"})
Book
sales
の例は次のとおりです。
@PofExtractor(path = "sales", type Long.class)
親トピック: ExtractorBinding注釈の使用
カスタムExtractorBinding注釈の使用
組込みのエクストラクタ・バインディングが適切でない場合、またはカスタムのValueExtractor
実装が必要な場合、対応するcom.oracle.coherence.cdi.ExtractorFactory
実装を使用してカスタム・エクストラクタ・バインディング注釈を作成できます。
カスタム・エクストラクタを作成するには、次のステップを実行します。
- 必要な
ValueExtractor
を表すカスタム注釈クラスを作成します。 - カスタム
ValueExtractor
のインスタンスを生成するためのファクトリとなるカスタム注釈が付いたcom.oracle.coherence.cdi.ExtractorFactory
を実装するBeanクラスを作成します。 - ビューの注入ポイントにカスタム注釈を付けます。
親トピック: ExtractorBinding注釈の使用
カスタム・エクストラクタ注釈の作成
エクストラクタ注釈の作成は、@com.oracle.coherence.cdi.ExtractorBinding
注釈が付いた通常のJava注釈クラスの作成と同じです。
Coherence CDI拡張がValueExtractor
を表すことを認識できるように、次の新しい注釈にExtractorBinding
を付けることが最も重要な部分です。
@Inherited
@ExtractorBinding
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomExtractor {
}
親トピック: ExtractorBinding注釈の使用
カスタム・エクストラクタ・ファクトリの作成
カスタム注釈を作成した後、必要なValueExtractor
のインスタンスを生成するExtractorFactory
実装を作成できます。
@ApplicationScoped
@CustomExtractor
static class CustomExtractorSupplier
implements ExtractorFactory<CustomExtractor, Object, Object>
{
@Override
public ValueExtractor<Object, Object> create(CustomExtractor annotation)
{
return new CustomComplexExtractor();
}
}
- CDIで検出できるように、
CustomExtractorSupplier
クラスに@ApplicationScoped
という注釈が付けられています。 CustomExtractorSupplier
クラスには、ValueExtractor
インスタンスを作成する必要があるときにCoherence CDI拡張で検出できるように、新しいエクストラクタ・バインディング注釈@CustomExtractor
が付けられています。CustomExtractorSupplier
は、カスタムValueExtractor
実装を作成するExtractorFactory
インタフェースのcreate
メソッドを実装します。
親トピック: ExtractorBinding注釈の使用
注入ポイントへの注釈付け
カスタム注釈と注釈付きExtractorFactory
の両方があるため、ValueExtractor
を必要とする注入ポイントに新しい注釈を付けることができます。
@Inject
@View
@CustomExtractor
private NamedMap<Long, String> people;
ビューと同様に、カスタム・フィルタ・バインディング注釈をイベント・オブザーバに使用できます。たとえば、カスタム・エクストラクタを使用してイベントを変換する変換済イベントのみを受け取るイベント・オブザーバ・メソッドがある場合、次のようにカスタム・フィルタ・バインディング注釈を使用できます。
@CustomExtractor
private void onPerson(@Observes @MapName("people") EntryEvent<Long, String> event) {
親トピック: ExtractorBinding注釈の使用
MapEventTransformerBinding注釈の使用
Coherence CDIでは、キャッシュ・エントリまたはマップ・エントリのイベントを監視できるイベント・オブザーバがサポートされています。observer
メソッドにMapEventTransformerBinding
注釈を付けて、オブザーバが監視前に元のイベントにトランスフォーマを適用する必要があることを示すことができます。
イベントの詳細は、CDIオブザーバを使用したCoherenceサーバー側イベントの処理を参照してください。
組込みのMapEventTransformerBinding
注釈はありません。この機能は、カスタムのMapEventTransformer
実装の使用をサポートします。
MapEventTransformerBinding
注釈を作成して使用するには、次のステップを実行します。
- 必要な
MapEventTransformer
を表すカスタム注釈クラスを作成します。 - カスタム
MapEventTransformer
のインスタンスを生成するためのファクトリとなるカスタム注釈が付いたcom.oracle.coherence.cdi.MapEventTransformerFactory
を実装するBeanクラスを作成します。 - ビューの注入ポイントにカスタム注釈を付けます。
この項には次のトピックが含まれます:
カスタム・エクストラクタ注釈の作成
エクストラクタ注釈の作成は、@com.oracle.coherence.cdi.MapEventTransformerBinding
注釈が付いた通常のJava注釈クラスの作成と同じです。
Coherence CDI拡張がMapEventTransformer
を表すことを認識できるように、次の新しい注釈にMapEventTransformerBinding
を付けることが最も重要な部分です。
@Inherited
@MapEventTransformerBinding
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomTransformer {
}
カスタム・エクストラクタ・ファクトリの作成
カスタム注釈を作成した後、必要なMapEventTransformer
のインスタンスを生成するMapEventTransformerFactory
実装を作成できます。
@ApplicationScoped
@CustomTransformer
static class CustomExtractorSupplier
implements ExtractorFactory<CustomExtractor, Object, Object>
{
@Override
public ValueExtractor<Object, Object> create(CustomExtractor annotation)
{
return new CustomComplexExtractor();
}
}
- CDIで検出できるように、
CustomTransformerSupplier
クラスに@ApplicationScoped
という注釈が付けられています。 CustomTransformerSupplier
クラスには、MapEventTransformer
インスタンスを作成する必要があるときにCoherence CDI拡張で検出できるように、新しいエクストラクタ・バインディング注釈CustomTransformer
が付けられています。CustomTransformerSupplier
は、カスタムMapEventTransformer
実装を作成するMapEventTransformerFactory
インタフェースのcreate
メソッドを実装します。
CDIレスポンス・キャッシングの使用
CDIレスポンス・キャッシングを使用すると、Javaメソッドに透過的にキャッシュを適用できます。coherence-CDI
依存関係を追加すると、CDIレスポンス・キャッシングが有効になります。
pom.xml
ファイルで、次に示すようにcoherence-cdi
を依存関係として宣言します:<dependency>
<groupId>${coherence.groupId}</groupId>
<artifactId>coherence-cdi</artifactId>
<version>${coherence.version}</version>
</dependency>
ノート:
この機能は、累積パッチ更新(CPU) 35122413以降をインストールした後でのみ使用できます。この項には次のトピックが含まれます:
レスポンス・キャッシング注釈
レスポンス・キャッシングに使用される特定のキャッシュは、クラスまたはメソッドの@CacheName
および@SessionName
注釈で宣言できます。
次のレスポンス・キャッシング注釈がサポートされています:
@CacheAdd
@CacheAdd
注釈でマークされたメソッドは、常に起動され、その実行結果はキャッシュに格納されます。キーは、すべてのパラメータの値で構成されます(このケースでは、文字列パラメータname
のみ)。
@Path("{name}")
@POST
@CacheAdd
@CacheName("messages")
public Message addMessage(@PathParam("name") String name)
{
return new Message("Hello " + name);
}
親トピック: レスポンス・キャッシング注釈
@CacheGet
戻り値がキャッシュに存在する場合は、フェッチされて返されます。それ以外の場合は、ターゲット・メソッドが呼び出され、呼出し結果がキャッシュに格納されてから、コール元に返されます。
@Path("{name}")
@GET
@CacheGet
@CacheName("messages")
public Message getMessage(@PathParam("name") String name)
{
return new Message("Hello " + name);
}
親トピック: レスポンス・キャッシング注釈
@CachePut
@CacheValue
注釈付きパラメータの値はキャッシュに格納され、ターゲット・メソッドが呼び出され、呼出し結果がコール元に返されます。
この例では、渡されたメッセージは、値がname
パラメータとして渡されたキーのキャッシュに格納されます。
@Path("{name}")
@POST
@Consumes(MediaType.APPLICATION_JSON)
@CachePut
@CacheName("messages")
public Response putMessage(@CacheKey @PathParam("name") String name,
@CacheValue Message message)
{
return Response.status(Response.Status.CREATED).build();
}
親トピック: レスポンス・キャッシング注釈
@CacheRemove
この注釈は、キャッシュからキーを削除し、メソッド呼出しの結果を返します。
この例では、name
パラメータとして値が渡されたキーがキャッシュから削除されます。
@Path("{name}")
@DELETE
@CacheRemove
public Response removeMessage(@PathParam("name") String name)
{
return Response.ok().build();
}
親トピック: レスポンス・キャッシング注釈
@CacheKey
キャッシュ・キーは、@CacheValue
注釈で明示的に注釈付けされていないすべてのパラメータの値から組み立てられます。1つ以上のパラメータに@CacheKey
注釈が付けられている場合、それらのパラメータのみがキーの作成に使用されます。
この例では、lastName
およびfirstName
パラメータの値のみがキャッシュ・キーの作成に使用されます。
@Path("{lastName}/{firstName}")
@GET
@CacheGet
public Message getMessage(@PathParam("lastName") @CacheKey String lastName,
@PathParam("firstName") @CacheKey String firstName,
@HeaderParam("Accept-Language") String acceptLanguage)
{
return new Message("Hello " + firstName + " " + lastName);
}
親トピック: レスポンス・キャッシング注釈