Skip to content

Instantly share code, notes, and snippets.

@asufana
Last active December 14, 2015 02:59
Show Gist options
  • Save asufana/11105142 to your computer and use it in GitHub Desktop.
Save asufana/11105142 to your computer and use it in GitHub Desktop.
PlayFramework1 キャッシュ機構

PlayFramework1 キャッシュ機構

http://www.playframework-ja.org/documentation/1.2.7/cache

パフォーマンスの高いシステムを作成するため、データのキャッシュが必要になる場合があります。Play にはキャッシュライブラリがあり、分散環境下では Memcahed を使用します。

Memcached を設定しない場合、Play は JVM ヒープにデータを保存するスタンドアロンキャッシュを使用します。

public static void allProducts() {
    // キャッシュ取得
    List<Product> products = Cache.get("products", List.class);
    if(products == null) {
        products = Product.findAll();
        // キャッシュ登録
        Cache.set("products", products, "30mn");
    }
    render(products);
}

play.cacheパッケージ

クラス図

スタンドアロンキャッシュ実装

Ehcache を利用

EhcacheはオープンソースのJavaEEや軽量コンテナ等で広く使われているキャッシュ機構である。メモリとディスクストレージ、レプリケーション、リスナ、キャッシュローダー、キャッシュ拡張、キャッシュ例外ハンドラ、gzipキャッシュサーブレットフィルタ、RESTとSOAPのAPIといった機能を持つ。EhcacheはApache Licenseで利用できる。

Ehcacheは2003年にGreg Luckにより開発された。2009年、プロジェクトはTerracotta, Inc.により買収された。ソフトウェア自体は、引き続きオープンソースとされている。(Wikipedia

Cache.java

public abstract class Cache {
    // キャッシュ実装クラスのインスタンス保持
    public static CacheImpl cacheImpl;
    
    // 初期化
    public static void init() {
        // キャッシュ実装にmemcachedを利用する場合
        if (Play.configuration.getProperty("memcached", "disabled").equals("enabled")) {
            try {
                cacheImpl = MemcachedImpl.getInstance(true);
                Logger.info("Connected to memcached");
            } catch (Exception e) {
                Logger.error(e, "Error while connecting to memcached");
                Logger.warn("Fallback to local cache");
                cacheImpl = EhCacheImpl.getInstance();
            }
        // デフォルトキャッシュ機構を利用する場合
        } else {
            cacheImpl = EhCacheImpl.newInstance();
        }
    }

EhCacheImpl.java

public class EhCacheImpl implements CacheImpl {

    // シングルトンインスタンス保持
    private static EhCacheImpl uniqueInstance;

    // Ehcacheインスタンス保持
    CacheManager cacheManager;
    net.sf.ehcache.Cache cache;

    private static final String cacheName = "play";

    // コンストラクタ
    private EhCacheImpl() {
        this.cacheManager = CacheManager.create();
        this.cacheManager.addCache(cacheName);
        this.cache = cacheManager.getCache(cacheName);
    }

    // インスタンスを生成して取得
    public static EhCacheImpl newInstance() {
        uniqueInstance = new EhCacheImpl();
        return uniqueInstance;
    }

    // キャッシュ登録
    public void add(String key, Object value, int expiration) {
        if (cache.get(key) != null) {
            return;
        }
        Element element = new Element(key, value);
        element.setTimeToLive(expiration);
        cache.put(element);
    }

    // キャッシュ取得
    public Object get(String key) {
        Element e = cache.get(key);
        return (e == null) ? null : e.getValue();
    }

新しいキャッシュ機能

http://www.playframework-ja.org/documentation/1.1.1/releasenotes-1.1#anamecachea

アクションとテンプレートにより簡単にキャッシュを統合することができる 2 つの新機能を用意しました。最初に、 @play.cache.CacheFor アノテーションを追加することで、アクションの結果を容易にキャッシュすることができるようになりました。これは見せかけの静的ページを作るのにとても便利です。

@CacheFor("1h")
public static void index() {
	render();
}

@CacheForアノテーション

// Example: @CacheFor("1h")
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheFor {
    String value() default "1h";
    String id() default "";
}

アクション処理で@CacheForを処理する

    public static void invoke(Http.Request request, Http.Response response) {
        
            try {
                // @Before処理
                handleBefores(request);

                // メソッド処理
                Result actionResult = null;
                String cacheKey = null;

                // キャッシュ設定確認(GET/HEADメソッド時のみ)
                if ((request.method.equals("GET") || request.method.equals("HEAD"))
                      // @CacheForアノテーションが設定されていれば
                      && actionMethod.isAnnotationPresent(CacheFor.class)) {

                    cacheKey = actionMethod.getAnnotation(CacheFor.class).id();
                    if ("".equals(cacheKey)) {
                        // Getクエリストリングをキャッシュキーにする
                        cacheKey = "urlcache:" + request.url + request.querystring;
                    }
                    // キャッシュ取得
                    actionResult = (Result) play.cache.Cache.get(cacheKey);
                }

                // キャッシュ登録なければ
                if (actionResult == null) {
                    ControllerInstrumentation.initActionCall();
                    try {
                        //メソッド実行
                        inferResult(invokeControllerMethod(actionMethod));
                    } catch(Result result) {
                        actionResult = result;
                        // キャッシュ設定があれば、キャッシュする
                        if (cacheKey != null) {
                            play.cache.Cache.set(cacheKey, actionResult, actionMethod.getAnnotation(CacheFor.class).value());
                        }

Ehcacheデフォルト値

ehcache.xmlにて設定

maxElementsInMemory

メモリに格納する最大エントリ数(Playデフォルト10000件)

eternal

タイムアウト値は無視して保持するかどうか(Playデフォルトfalse)

timeToIdleSeconds

キャッシュのアイドル秒数(Playデフォルト120秒)

timeToLiveSeconds

キャッシュの有効秒数(Playデフォルト120秒)

overflowToDisk

メモリへの格納数をこえた場合にディスクに格納するかどうか(Playデフォルトfalse)

maxElementsOnDisk

ディスクに格納する最大エントリ数(Playデフォルト10000000件)

diskPersistent

再起動する際にディスクキャッシュを永続化するかどうか(Playデフォルトfalse)

diskExpiryThreadIntervalSeconds

ディスクキャッシュの期限をチェック間隔秒(Playデフォルト120秒)

memoryStoreEvictionPolicy

メモリに格納するエントリが最大値に達したときの振る舞いをLRU(最も古く使われたもの)、FIFO(最も古く登録したもの)、LFU(最も使われていないもの)のいずれかで指定(PlayデフォルトLFU)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment