15
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Spring 4.3 キャッシュ関連の主な変更点

Last updated at Posted at 2016-05-28

今回は、Spring Framework 4.3の変更点紹介シリーズの第3回で、キャッシュ関連の変更点を紹介します。

シリーズ

動作検証環境

  • Spring Framework 4.3.0.RELEASE
  • Spring Boot 1.4.0.BUILD-SNAPSHOT (2016/6/11時点)

Caching Improvements

今回は、キャッシュ関連(@Cacheable)の主な変更点をみていきます。

No キャッシュ関連の主な変更点
1 マルチスレッド下での同時アクセス時に、キャッシュデータのロード処理を同期化できるようになります。 また、この変更に伴いCacheインターフェースにget(Object key, Callable<T> valueLoader)メソッドが追加されています。
2 @Cacheableなどキャッシュ制御用アノテーションのcondition属性に指定するSpEL中で、DIコンテナに登録されているBeanを参照できるようになります。
3 ConcurrentMapCacheで管理するオブジェクトをシリアライズできるようになります。
4 @Cacheableなどのキャッシュ制御用アノテーションをメタアノテーションとして利用できるようになります。

キャッシュデータのロード処理を同期化できる :thumbsup:

Spring 4.3から、@Cacheablesync属性が追加され、trueを設定するとキャッシュデータのロード処理が同期化できるようになります。ここで注意しておきたいのは、sync属性に指定した値はあくまで「ヒント」であり、実際に同期化するかはorg.springframework.cache.Cacheの実装クラスや利用するライブラリの実装に委ねられているということです。
ちなみに・・・Spring Frameworkが提供するConcurrentMapベースのCache実装(ConcurrentMapCache)は、Cacheオブジェクト単位でsynchronizedする実装になっています。なお、sync属性のデフォルト値はfalse(同期化しない)です。

なお、以降の説明では、キャッシュ実装としてConcurrentMapCacheを使用する前提で説明をします。ちなみに、@Cacheable(アノテーション駆動のキャッシュ制御)を利用する場合は、最低限以下のBean定義が必要になります。

@EnableCaching // アノテーション駆動のキャッシュ制御を有効にする
@Configuration
public class CacheConfig {
    @Bean
    CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("configs");  // CacheManagerをBean定義する
    }
}

データのロード処理を同期化しない(デフォルト)

同期化しない場合は、Spring 4.2と何もかわりません。

@Service
@CacheConfig(cacheNames = "configs")
public class ConfigService {
    @Cacheable // sync属性を省略 or sync = false
    public Config get(String key) {
        // ...
    }
}

複数スレッドから同時にアクセスがあった場合は、キャッシュキー(メソッドの引数)が一緒でも同時にメソッドが呼び出される可能性があります。なお、実際にキャッシュされるのは、メソッドが先に呼びだされたスレッドの返り値になります。

spr43-cacheable-sync-false.png

データのロード処理をを同期化する

Spring 4.3から追加された@Cacheablesync属性をtrueにするだけです。

@Cacheable(sync = true) // sync属性をtrueにする
public Config get(String key) {
    // ...
}

キーに対応するオブジェクトがキャッシュされていない場合は、Cacheオブジェクト自体を同期化(synchronized)してからデータをロードするメソッド(@Cacheableメソッド)を呼び出します。

spr43-cacheable-sync-true.png

同期化する場合は、同期化の範囲を理解しておいた方がよいでしょう。ConcurrentMapCacheの実装では、同期化の範囲がキーではなく、Cacheオブジェクト自体になります。これをRDBMSに置き換えると、同期化の範囲が「行」ではなく「テーブル」になるイメージです。

なお、キャッシュデータのロード処理を同期化する場合は、以下がサポートされないので注意してください。

  • @Cacheableunless属性の利用
  • 複数キャッシュの指定
  • 他のキャッシュ操作(@CachePut, @CacheEvictなど)との併用

@Cacheableなどのcondition属性でBeanを参照ができる :thumbsup:

Spring 4.3から、@Cacheable, @CachePut, @CacheEvictのcondition属性に指定するSpEL中で、DIコンテナに登録されているBeanを参照できるようになります。 この改善により、キャッシュ操作の対象データを絞り込む条件をダイナミックに切り替えることができます。なお、SpELからBeanを参照する方法は「@EventListenerのcondition属性でBeanを参照ができる」をごらんください。

ConcurrentMapCacheで管理するオブジェクトをシリアライズできる :thumbsup:

Spring 4.3から、ConcurrentMapCacheで管理するオブジェクトをシリアライズすることができるようになります。この改善により、キャッシュ内で管理しているオブジェクトと、キャッシュから返却するオブジェクトを別のインスタンスにすることができます。
たとえば、キャッシュから取得したオブジェクトの状態が変更されたとしても、キャッシュ内で管理しているオブジェクトの状態を変更したくない場合に有効な仕組みです。ただし、キャッシュからオブジェクトを取得する度に、byte配列をオブジェクトにするデシリアライズ処理が実行されるため、同じインスタンスを返却する方法に比べると、処理コストがかかることは意識しておきましょう。

キャッシュするオブジェクトをシリアライズする場合は、ConcurrentMapCacheManagerstoreByValueプロパティにtrueを指定すればよいだけ・・・だと思ったのですが・・・、実際に動かしてみるとシリアライズされませんでした・・・ :cry: 。→ 【2016/5/31】 Spring JIRAのIssue(SPR-14314)にて修正されました :smile:

シリアライズ機能を有効にするためBean定義例
@EnableCaching
@Configuration
public class CacheConfig {
    @Bean
    CacheManager cacheManager() {
        ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager("configs");
        cacheManager.setStoreByValue(true); // storeByValueプロパティをtrueにする
        return cacheManager;
    }
}

なお、この機能を使用する場合は、キャッシュするクラスにjava.io.Serializableを実装しておく必要があります。

package com.example;

import java.io.Serializable;

public class Config implements Serializable { // Serializableを実装する
    private String key;
    private String value;
    // ...
}

@Cacheableなどをメタアノテーションとして使用できる :thumbsup:

Spring 4.3から、@Cacheable, @CacheEvict, @CachePut, @Cachingをメタアノテーションとして利用できるようになります。
どういう切り口でカスタムアノテーションを作るかは自由ですが、ここでは、同期化が必要になるキャッシュを表現するカスタムアノテーションを使ってみます。同期化が必要になるのは・・・おそらく一貫性の担保が必要なキャッシュだと思うので、「@ConsistencyCacheable」という名前にしてみます。

@Cacheable(sync = true) // メタアノテーションとして@Cacheableを指定
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ConsistencyCacheable {
}

@Cacheable(sync = true)ではなく、作成したカスタムアノテーション(@ConsistencyCacheable)を使用します。

@ConsistencyCacheable // カスタムアノテーションを指定
public Config get(String key) {
    // ...
}

まとめ

今回は、キャッシュ関連の主な変更点を紹介しました。データのロード処理の同期化やオブジェクトのシリアライズ化のサポートなど、アプリケーションの安全性を高める仕組みが導入されたことで、エンタープライズアプリケーション開発での実用性が増した感じがします。次回は、「JMS関連の主な変更点」を紹介する予定です。

参考サイト

備考

オブジェクトのシリアラズ化の挙動

Spring 4.3からConcurrentMapCacheで管理するオブジェクトをシリアライズできるように改善されたが、単純にsotreByValueプロパティにtrueを指定しても機能が有効にならなかった・・・。バグの疑いがあるため、SPR-14314を作成しておいた。

【2016/5/31】
修正されました。

15
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?