1. 概要

簡単に言うと、JCacheはJavaの標準キャッシュAPIです。 このチュートリアルでは、JCacheとは何か、およびJCacheの使用方法を確認します。

2. Mavenの依存関係

JCacheを使用するには、pom.xmlに次の依存関係を追加する必要があります。

<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
    <version>1.0.0-PFD</version>
</dependency>

ライブラリの最新バージョンはMaven中央リポジトリにあることに注意してください。

また、APIの実装をpom.xmlに追加する必要があります。 ここではHazelcastを使用します。

<dependency>
    <groupId>com.hazelcast</groupId>
    <artifactId>hazelcast</artifactId>
    <version>3.9-EA</version>
</dependency>

最新バージョンのHazelcastは、 Maven CentralRepositoryにもあります。

3. JCacheの実装

JCacheは、さまざまなキャッシングソリューションによって実装されます。

  • JCacheリファレンス実装
  • ヘーゼルキャスト
  • Oracle Coherence
  • Terracotta Ehcache
  • インフィニスパン

他のリファレンス実装とは異なり、同時実行の問題が発生するため、本番環境でJCacheリファレンス実装を使用することはお勧めしません。

4. メインコンポーネント

4.1. キャッシュ

Cache インターフェースには、次の便利なメソッドがあります。

  • get() –要素のキーをパラメーターとして受け取り、要素の値を返します。 キーがキャッシュに存在しない場合は、nullを返します。
  • getAll() –複数のキーをSetとしてこのメソッドに渡すことができます。 このメソッドは、指定されたキーと関連する値をMapとして返します。
  • getAndRemove() –メソッドはそのキーを使用して値を取得し、Cacheから要素を削除します
  • put()キャッシュに新しいアイテムを挿入します
  • clear()キャッシュ内のすべての要素を削除します
  • containsKey()Cacheに特定のキーが含まれているかどうかを確認します

ご覧のとおり、メソッドの名前はほとんど自明です。 これらのメソッドおよびその他のメソッドの詳細については、Javadocにアクセスしてください。

4.2. CacheManager

CacheManager は、APIの最も重要なインターフェースの1つです。 これにより、キャッシュを確立、構成、および閉じることができます。

4.3. CachingProvider

CachingProvider は、CacheManagersのライフサイクルを作成および管理できるようにするインターフェイスです。

4.4. 構成

Configuration は、Cachesを構成できるようにするインターフェースです。 これには、MutableConfigurationとサブインターフェイスCompleteConfigurationという1つの具体的な実装があります。

5. キャッシュの作成

単純なキャッシュを作成する方法を見てみましょう。

CachingProvider cachingProvider = Caching.getCachingProvider();
CacheManager cacheManager = cachingProvider.getCacheManager();
MutableConfiguration<String, String> config
  = new MutableConfiguration<>();
Cache<String, String> cache = cacheManager
  .createCache("simpleCache", config);
cache.put("key1", "value1");
cache.put("key2", "value2");
cacheManager.close();

私たちがしているのは:

  • CachingProviderオブジェクトの作成。これを使用してCacheManagerオブジェクトを作成します。
  • MutableConfigurationオブジェクトの作成。これはConfigurationインターフェースの実装です。
  • 以前に作成したCacheManagerオブジェクトを使用してCacheオブジェクトを作成する
  • すべてのエントリを入れて、Cacheオブジェクトにキャッシュする必要があります
  • CacheManager を閉じて、Cacheによって使用されているリソースを解放します

pom.xml でJCacheの実装を提供しない場合、次の例外がスローされます。

javax.cache.CacheException: No CachingProviders have been configured

これは、JVMが getCacheManager()メソッドの具体的な実装を見つけることができなかったためです。

6. EntryProcessor

EntryProcessor を使用すると、 Cache に再度追加しなくても、アトミック操作を使用してCacheエントリを変更できます。 これを使用するには、EntryProcessorインターフェイスを実装する必要があります。

public class SimpleEntryProcessor
  implements EntryProcessor<String, String, String>, Serializable {
    
    public String process(MutableEntry<String, String> entry, Object... args)
      throws EntryProcessorException {

        if (entry.exists()) {
            String current = entry.getValue();
            entry.setValue(current + " - modified");
            return current;
        }
        return null;
    }
}

それでは、EntryProcessor実装を使用してみましょう。

@Test
public void whenModifyValue_thenCorrect() {
    this.cache.invoke("key", new SimpleEntryProcessor());
 
    assertEquals("value - modified", cache.get("key"));
}

7. イベントリスナー

イベントリスナーを使用すると、EventType列挙型で定義されているイベントタイプのいずれかをトリガーしたときにアクションを実行できます。

  • 作成した
  • 更新しました
  • 削除されました
  • 期限切れ

まず、使用するイベントのインターフェースを実装する必要があります。

たとえば、CREATEDおよびUPDATEDイベントタイプを使用する場合は、インターフェイスCacheEntryCreatedListenerおよびCacheEntryUpdatedListenerを実装する必要があります。

例を見てみましょう:

public class SimpleCacheEntryListener implements
  CacheEntryCreatedListener<String, String>,
  CacheEntryUpdatedListener<String, String>,
  Serializable {
    
    private boolean updated;
    private boolean created;
    
    // standard getters
    
    public void onUpdated(
      Iterable<CacheEntryEvent<? extends String,
      ? extends String>> events) throws CacheEntryListenerException {
        this.updated = true;
    }
    
    public void onCreated(
      Iterable<CacheEntryEvent<? extends String,
      ? extends String>> events) throws CacheEntryListenerException {
        this.created = true;
    }
}

それでは、テストを実行してみましょう。

@Test
public void whenRunEvent_thenCorrect() throws InterruptedException {
    this.listenerConfiguration
      = new MutableCacheEntryListenerConfiguration<String, String>(
        FactoryBuilder.factoryOf(this.listener), null, false, true);
    this.cache.registerCacheEntryListener(this.listenerConfiguration);
    
    assertEquals(false, this.listener.getCreated());
    
    this.cache.put("key", "value");
 
    assertEquals(true, this.listener.getCreated());
    assertEquals(false, this.listener.getUpdated());
    
    this.cache.put("key", "newValue");
 
    assertEquals(true, this.listener.getUpdated());
}

8. CacheLoader

CacheLoaderを使用すると、はリードスルーモードを使用して、キャッシュをメインデータストアとして扱い、そこからデータを読み取ることができます

実際のシナリオでは、キャッシュに実際のストレージからデータを読み取らせることができます。

例を見てみましょう。 まず、CacheLoaderインターフェイスを実装する必要があります。

public class SimpleCacheLoader
  implements CacheLoader<Integer, String> {

    public String load(Integer key) throws CacheLoaderException {
        return "fromCache" + key;
    }
    
    public Map<Integer, String> loadAll(Iterable<? extends Integer> keys)
      throws CacheLoaderException {
        Map<Integer, String> data = new HashMap<>();
        for (int key : keys) {
            data.put(key, load(key));
        }
        return data;
    }
}

それでは、CacheLoaderの実装を使用してみましょう。

public class CacheLoaderTest {
    
    private Cache<Integer, String> cache;
    
    @Before
    public void setup() {
        CachingProvider cachingProvider = Caching.getCachingProvider();
        CacheManager cacheManager = cachingProvider.getCacheManager();
        MutableConfiguration<Integer, String> config
          = new MutableConfiguration<>()
            .setReadThrough(true)
            .setCacheLoaderFactory(new FactoryBuilder.SingletonFactory<>(
              new SimpleCacheLoader()));
        this.cache = cacheManager.createCache("SimpleCache", config);
    }
    
    @Test
    public void whenReadingFromStorage_thenCorrect() {
        for (int i = 1; i < 4; i++) {
            String value = cache.get(i);
 
            assertEquals("fromCache" + i, value);
        }
    }
}

9. 結論

このチュートリアルでは、JCacheとは何かを確認し、いくつかの実用的なシナリオでその重要な機能のいくつかを調べました。

いつものように、このチュートリアルの完全な実装は、GitHubにあります。