第29章 Infinispan CDI モジュール

29.1. Infinispan CDI モジュール

Infinispan の infinispan-cdi モジュールには Context and Dependency Injection (CDI) が含まれています。 infinispan-cdi モジュールは以下を提供します。

  • Cache API を使用した設定およびインジェクション。
  • キャッシュリスナーと CDI イベントシステム間のブリッジ。
  • JCACHE をキャッシュするアノテーションの部分サポート。

29.2. Infinispan CDI の使用

29.2.1. Infinispan CDI の要件

以下は Infinispan CDI モジュールを Red Hat JBoss Data Grid と使用するための要件になります。

  • 最新バージョンの infinispan-cdi モジュールを使用してください。
  • 依存関係の情報を正しく設定してください。

29.2.2. CDI Maven 依存関係の設定

CDI モジュールは各デプロイメント型の Infinispan jar に含まれています。他に必要な依存関係はありません。

ライブラリーモード

ライブラリーモードでは、infinispan-embedded アーティファクトに CDI モジュールが含まれています。以下の例のように依存関係として追加する必要があります。

<dependency>
    <groupId>org.infinispan</groupId>
    <artifactId>infinispan-embedded</artifactId>
    <version>${infinispan.version}</version>
</dependency>

リモートクライアントサーバーモード

リモートクライアントサーバーモードでは、infinispan-remote アーティファクトに CDI モジュールが含まれています。以下の例のように依存関係として追加する必要があります。

<dependency>
    <groupId>org.infinispan</groupId>
    <artifactId>infinispan-remote</artifactId>
    <version>${infinispan.version}</version>
</dependency>

29.3. Infinispan CDI モジュールの使用

29.3.1. Infinispan CDI モジュールの使用

Infinispan CDI モジュールは以下の目的に使用できます。

  • Infinispan キャッシュを CDI Bean および Java EE コンポーネントに設定およびインジェクトする。
  • キャッシュマネージャーの設定。
  • CDI アノテーションを使用した格納および取得の制御。

29.3.2. Infinispan キャッシュの設定およびインジェクション

29.3.2.1. Infinispan キャッシュのインジェクション

Infinispan キャッシュは、プロジェクトの CDI Bean にインジェクトできる複数のコンポーネントの 1 つです。

以下のコードスニペットはキャッシュインスタンスを CDI Bean にインジェクトする方法を示しています。

public class MyCDIBean {
    @Inject
    Cache<String, String> cache;
}

29.3.2.2. リモート Infinispan キャッシュのインジェクション

リモート Infinispan キャッシュをインジェクトするには、普通のキャッシュをインジェクトするコードスニペットを次のように若干変更します。

public class MyCDIBean {
    @Inject
    RemoteCache<String, String> remoteCache;
}

29.3.2.3. インジェクションのターゲットキャッシュの設定

29.3.2.3.1. インジェクションのターゲットキャッシュの設定

インジェクションのターゲットキャッシュを設定するには、次の 3 つのステップに従います。

  1. 修飾子アノテーションを作成します。
  2. プロデューサークラスを追加します。
  3. 希望のクラスをインジェクトします。
29.3.2.3.2. 修飾子アノテーションの作成

CDI を使用して特定のキャッシュを返すには、次のようにカスタムのキャッシュ修飾子アノテーションを作成します。

カスタムキャッシュ修飾子

@javax.inject.Qualifier
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SmallCache {}

作成した @SmallCache 修飾子を使用して、特定のキャッシュの作成方法を指定します。

29.3.2.3.3. プロデューサークラスの追加

以下のコードスニペットは、@SmallCache 修飾子 (前のステップで作成) がどのようにキャッシュの作成方法を指定するかを示しています。

@SmallCache 修飾子の使用

import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.cdi.ConfigureCache;
import javax.enterprise.inject.Produces;

public class CacheCreator {
    @ConfigureCache("smallcache")
    @SmallCache
    @Produces
    public Configuration specialCacheCfg() {
        return new ConfigurationBuilder()
                   .eviction()
                       .strategy(EvictionStrategy.LRU)
                       .maxEntries(10)
                   .build();
    }
}

コードスニペットの要素は次のとおりです。

  • @ConfigureCache はキャッシュの名前を指定します。
  • @SmallCache はキャッシュ修飾子です。
29.3.2.3.4. 希望のクラスのインジェクト

以下のように @SmallCache 修飾子と新しいプロデューサークラスを使用して、特定のキャッシュを CDI Bean にインジェクトします。

public class MyCDIBean {
    @Inject @SmallCache
    Cache<String, String> mySmallCache;
}

29.3.3. CDI を用いたキャッシュマネージャーの設定

29.3.3.1. CDI を用いたキャッシュマネージャーの設定

Red Hat JBoss Data Grid のキャッシュマネージャー (組み込みとリモートの両方) は CDI を使用して設定できます。設定するキャッシュマネージャーが組み込みかリモートであるかに関わらず、最初の手順として、アノテーションを付けてプロデューサーとして動作するデフォルト設定を指定します。

29.3.3.2. デフォルト設定の指定

Red Hat JBoss Data Grid 設定に対してプロデューサーとしてアノテーション付けされたメソッドを指定し、デフォルトの Infinispan 設定を置き換えます。以下の設定例はこの手順を示しています。

デフォルト設定の指定

public class Config {
    @Produces
    public Configuration defaultEmbeddedConfiguration () {
        return new ConfigurationBuilder()
                         .eviction()
                                 .strategy(EvictionStrategy.LRU)
                                 .maxEntries(100)
                         .build();
    }
}

注記

他の修飾子が提供されない場合、CDI は @Default 修飾子を追加します。

@Produces アノテーションが設定インスタンスを返すメソッドに配置された場合、Configuration オブジェクトが必要なときにメソッドが呼び出されます。

この設定例では、作成後に設定され返される新しい Configuration オブジェクトが作成されます。

29.3.3.3. 組み込みキャッシュマネージャーの作成のオーバーライド

前提条件

デフォルト設定の指定を参照してください。

非クラスターキャッシュの作成

プロデューサーメソッドにアノテーションが付けられた後、以下のように EmbeddedCacheManager の作成時にこのメソッドが呼び出されます。

public class Config {

    @Produces
    @ApplicationScoped
    public EmbeddedCacheManager defaultEmbeddedCacheManager() {
        Configuration cfg = new ConfigurationBuilder()
                                    .eviction()
                                            .strategy(EvictionStrategy.LRU)
                                            .maxEntries(150)
                                    .build();
        return new DefaultCacheManager(cfg);
    }
}

@ApplicationScoped アノテーションはメソッドが 1 度だけ呼び出されることを指定します。

クラスターキャッシュの作成

以下の設定は、クラスターキャッシュの作成が可能な EmbeddedCacheManager の作成に使用できます。

public class Config {

	@Produces
	@ApplicationScoped
	public EmbeddedCacheManager defaultClusteredCacheManager() {
		GlobalConfiguration g = new GlobalConfigurationBuilder()
				.clusteredDefault()
				.transport()
				.clusterName("InfinispanCluster")
				.build();
		Configuration cfg = new ConfigurationBuilder()
				.eviction()
				.strategy(EvictionStrategy.LRU)
				.maxEntries(150)
				.build();
		return new DefaultCacheManager(g, cfg);
	}
}

EmbeddedCacheManager を生成するメソッドの呼び出し

非クラスターメソッドの @Produces アノテーションが付けられたメソッドは Configuration オブジェクトを生成します。クラスターキャッシュの例で @Produces アノテーションが付けられたメソッドは EmbeddedCacheManager オブジェクトを生成します。

以下のように CDI Bean にインジェクションを追加し、適切にアノテーションが付けられたメソッドを呼び出します。これにより EmbeddedCacheManager が生成され、起動時にコードにインジェクトされます。

EmbeddedCacheManager の生成

...
@Inject
EmbeddedCacheManager cacheManager;
...

29.3.3.4. リモートキャッシュマネージャーの設定

RemoteCacheManager は、以下のように EmbeddedCacheManagers と似た方法で設定されます。

リモートキャッシュマネージャーの設定

public class Config {
	@Produces
	@ApplicationScoped
	public RemoteCacheManager defaultRemoteCacheManager() {
           Configuration conf = new ConfigurationBuilder().addServer().host(ADDRESS).port(PORT).build();
            return new RemoteCacheManager(conf);
	}
}}

29.3.3.5. 単一クラスでの複数のキャッシュマネージャーの設定

単一のクラスを使用して、作成された修飾子を基に複数のキャッシュマネージャーおよびリモートキャッシュマネージャーを設定できます。以下に例を示します。

複数のキャッシュマネージャーの設定

public class Config {
    @Produces
    @ApplicationScoped
    public org.infinispan.manager.EmbeddedCacheManager
    defaultEmbeddedCacheManager() {
        Configuration cfg = new ConfigurationBuilder()
                .eviction()
                .strategy(EvictionStrategy.LRU)
                .maxEntries(150)
                .build();
        return new DefaultCacheManager(cfg);
    }

    @Produces
    @ApplicationScoped
    @DefaultClustered
    public org.infinispan.manager.EmbeddedCacheManager
    defaultClusteredCacheManager() {
        GlobalConfiguration g = new GlobalConfigurationBuilder()
                .clusteredDefault()
                .transport()
                .clusterName("InfinispanCluster")
                .build();
        Configuration cfg = new ConfigurationBuilder()
                .eviction()
                .strategy(EvictionStrategy.LRU)
                .maxEntries(150)
                .build();
        return new DefaultCacheManager(g, cfg);
    }

    @Produces
    @ApplicationScoped
    @DefaultRemote
    public RemoteCacheManager
    defaultRemoteCacheManager() {
        org.infinispan.client.hotrod.configuration.Configuration conf = new org.infinispan.client.hotrod.configuration.ConfigurationBuilder().addServer().host(ADDRESS).port(PORT).build();
        return new RemoteCacheManager(conf);
    }

    @Produces
    @ApplicationScoped
    @RemoteCacheInDifferentDataCentre
    public RemoteCacheManager newRemoteCacheManager() {
        org.infinispan.client.hotrod.configuration.Configuration confid = new org.infinispan.client.hotrod.configuration.ConfigurationBuilder().addServer().host(ADDRESS_FAR_AWAY).port(PORT).build();
        return new RemoteCacheManager(confid);
    }
}

29.4. CDI アノテーションを使用した格納および取得

29.4.1. キャッシュアノテーションの設定

特定の CDI アノテーションは JCache (JSR-107) 仕様で受け入れられます。含まれるアノテーションはすべて javax.cache パッケージにあります。

アノテーションインターセプトメソッドは CDI Bean を呼び出し、インターセプトの結果として格納および取得タスクを実行します。

重要

CDI はリモートクライアントサーバーモードとライブラリーモードの両方でサポートされますが、@CachePut、@CacheRemove、@CacheRemoveAll、@CacheResult などのアノテーションはリモードクライアントサーバーモードでは使用できません。

29.4.2. キャッシュアノテーションの有効化

JBoss Data Grid には、使用方法に応じてインターセプターが 2 セット含まれています。beans.xml ファイルを使用するとインターセプターを CDI Bean アーカイブに追加できます。

オプション 1: CDI インターセプター

以下のコードを追加すると、InjectedCacheResultInterceptorInjectedCachePutInterceptorInjectedCacheRemoveEntryInterceptor、および InjectedCacheRemoveAllInterceptor などのインターセプターが追加されます。

CDI インターセプターの追加

<beans xmlns="http://java.sun.som/xml/ns/javaee"
       xmlns:xsi="http://www/w3/org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd" >
	<interceptors>
		<class>org.infinispan.jcache.annotation.InjectedCacheResultInterceptor</class>
		<class>org.infinispan.jcache.annotation.InjectedCachePutInterceptor</class>
		<class>org.infinispan.jcache.annotation.InjectedCacheRemoveEntryInterceptor</class>
		<class>org.infinispan.jcache.annotation.InjectedCacheRemoveAllInterceptor</class>
	</interceptors>
</beans>

オプション 2: JCache インターセプター

以下のコードを追加すると CacheResultInterceptorCachePutInterceptorCacheRemoveEntryInterceptor、および CacheRemoveAllInterceptor などのインターセプターが追加されます。

JCache インターセプターの追加

<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

   <interceptors>
      <class>org.infinispan.jcache.annotation.CacheResultInterceptor</class>
      <class>org.infinispan.jcache.annotation.CachePutInterceptor</class>
      <class>org.infinispan.jcache.annotation.CacheRemoveEntryInterceptor</class>
      <class>org.infinispan.jcache.annotation.CacheRemoveAllInterceptor</class>
   </interceptors>

</beans>

注記

Red Hat JBoss Data Grid が javax.cache アノテーションを使用するには、記載されているインターセプターが beans.xml ファイルに存在する必要があります。

29.4.3. メソッド呼び出しの結果をキャッシュ

29.4.3.1. メソッド呼び出しの結果をキャッシュ

今後のアクセスのために結果をキャッシュに保存することは、時間またはリソース集約型の操作で一般的に行われます。以下のコードはこのような操作の例になります。

public String toCelsiusFormatted(float fahrenheit) {
	return
		NumberFormat.getInstance()
		.format((fahrenheit * 5 / 9) - 32)
		+ " degrees Celsius";
}

一般的には、メソッド呼び出しの結果をキャッシュし、次に結果が必要になるときにキャッシュをチェックします。以下は、このような操作の結果をキャッシュで検索するコードスニペットの例になります。結果が見つからない場合、コードスニペットは toCelsiusFormatted を再実行し、結果をキャッシュに格納します。

float f = getTemperatureInFahrenheit();
Cache<Float, String>
	fahrenheitToCelsiusCache = getCache();
String celsius =
	fahrenheitToCelsiusCache = get(f);
     if (celsius == null) {
	     celsius = toCelsiusFormatted(f);
	     fahrenheitToCelsiusCache.put(f, celsius);
     }

このような場合、Infinispan CDI モジュールを使用すると、関連する例で余分なコードを削除できます。以下のように、メソッドに @CacheResult アノテーションを付けます。

@javax.cache.annotation.CacheResult
public String toCelsiusFormatted(float fahrenheit) {
	return NumberFormat.getInstance()
	.format((fahrenheit * 5 / 9) - 32)
	+ " degrees Celsius";
}

アノテーションにより、Infinispan はキャッシュをチェックし、結果が見つからなかった場合は toCelsiusFormatted() メソッドを呼び出します。

注記

Infinispan CDI モジュールでは、保存した結果のキャッシュをチェックできますが、これは適用前に注意して考慮する必要があります。呼び出しの結果が常に最新のデータである必要がある場合やキャッシュの読み取りにリモートネットワークの検索やキャッシュローダーからのデシリアライズが必要である場合、コールメソッド呼び出し前のキャッシュのチェックは逆効果になる可能性があります。

29.4.3.2. 使用するキャッシュの指定

以下のオプションの属性 (cacheName) を @CacheResult アノテーションに追加し、メソッドコールの結果をチェックするキャッシュを指定します。

@CacheResult(cacheName = "mySpecialCache")
public String doSomething(String parameter) {
<!-- Additional configuration information here -->
}

29.4.3.3. キャッシュされた結果のキャッシュキー

デフォルトでは、@CacheResult アノテーションはキャッシュから取得された結果のキーを作成します。このキーは、関連するメソッドのすべてのパラメーターの組み合わせで構成されます。

次のように @CacheKey アノテーションを使用してカスタムキーを作成します。

カスタムキーの作成

@CacheResult
public String doSomething
	(@CacheKey String p1,
	@CacheKey String p2,
	String dontCare) {
<!-- Additional configuration information here -->
}

この例では、キャッシュキーの作成に p1p2 のみが値として使用されます。キャッシュキーの判断には dontCare の値は使用されません。

29.4.3.4. カスタムキーの生成

次のようにカスタムキーを生成します。

import javax.cache.annotation.CacheKey;
import javax.cache.annotation.CacheKeyGenerator;
import javax.cache.annotation.CacheKeyInvocationContext;
import java.lang.annotation.Annotation;

public class MyCacheKeyGenerator implements CacheKeyGenerator {

   @Override
   public CacheKey generateCacheKey(CacheKeyInvocationContext<? extends Annotation> ctx) {

      return new MyCacheKey(
            ctx.getAllParameters()[0].getValue()
      );
   }
}

このメソッドはカスタムキーを構築します。このキーは呼び出しコンテキストの最初のパラメーターによって生成された値の一部として渡されます。

カスタムのキー生成スキームを指定するには、以下のように任意のパラメーター cacheKeyGenerator@CacheResult アノテーションに追加します。

@CacheResult(cacheKeyGenerator = MyCacheKeyGenerator.class)
public void doSomething(String p1, String p2) {
<!-- Additional configuration information here -->
}

提供されたメソッドを使用し、p1 にカスタムキーが含まれます。

29.4.4. キャッシュ操作

29.4.4.1. キャッシュエントリーの更新

@CachePut アノテーションが含まれるメソッドが呼び出されると、パラメーター (通常は @CacheValue アノテーションが付けられたメソッドに渡されます) はキャッシュに格納されます。

@CachePut アノテーションが付けられたメソッドの例

import javax.cache.annotation.CachePut;
import javax.cache.annotation.CacheKey;
import javax.cache.annotation.CacheValue;

@CachePut (cacheName = "personCache")
public void updatePerson
	(@CacheKey long personId,
	@CacheValue Person newPerson) {
<!-- Additional configuration information here -->
	}

@CachePut メソッドの cacheName および cacheKeyGenerator を使用するとさらにカスタマイズすることができます。また、呼び出されたメソッドの一部のパラメーターに @CacheKey アノテーションを付けるとキーの生成を制御できます。

キャッシュされた結果のキャッシュキーも参照してください

29.4.4.2. キャッシュからのエントリーの削除

以下は、キャッシュからエントリーを削除するために使用される @CacheRemoveEntry アノテーションが付けられたメソッドの例になります。

キャッシュからエントリーを削除

import javax.cache.annotation.CacheRemoveEntry;
import javax.cache.annotation.CacheKey;

@CacheRemoveEntry (cacheName = "cacheOfPeople")
public void changePersonName
	(@CacheKey long personId,
	string newName) {
<!-- Additional configuration information here -->
	}

このアノテーションは、任意の cacheName および cacheKeyGenerator 属性を受け入れます。

29.4.4.3. キャッシュの消去

@CacheRemoveAll メソッドを呼び出して、キャッシュからすべてのエントリーを消去します。

@CacheRemoveAll を使用してキャッシュからすべてのエントリーを消去

import javax.cache.annotation.CacheRemoveAll;

@CacheRemoveAll (cacheName = "statisticsCache")
public void resetStatistics() {
<!-- Additional configuration information here -->
}

例のとおり、このアノテーションは任意の cacheName 属性を受け入れます。