文系プログラマによるTIPSブログ

文系プログラマ脳の私が開発現場で学んだ事やプログラミングのTIPSをまとめています。

EHCacheでjavaで簡単にキャッシュを扱う!

javaのキャッシュライブラリについて紹介。

・複雑なのは嫌だよ。簡単なのないの?
・キャッシュの寿命は設定ファイルで自動で管理してよ。
・設定ファイル沢山書きたくないよ。
・依存jarが多いのは嫌だよ。導入し難いし。

という方にオススメです。
その名は「EHCache」。
導入は簡単です。ざっくり4ステップで動きます。
必要なファイルもehcache.jar、ehcache.xml、ehcache.xsdの3ファイルなので導入も楽です。

1,ダウンロードする
http://ehcache.org/downloads/catalog

2,ビルドパスに通す。
普通にjarをビルドパスに通します。

3,設定ファイルをビルドパス上に配置する。
必要なのは「ehcache.xml」「ehcache.xsd」の2ファイル。src/main/resources辺りに配置すればよいです。
ehcache.xsdは、 http://ehcache.org/ehcache.xsd これをダウンロードします。
ehacache.xmlは、自分で作成します。公式サイトにサンプルはあります。http://www.ehcache.org/documentation/user-guide/configuration
面倒な方は私が実際使っているxmlをサンプルとして使ってみて下さい。

<?xml version="1.0" encoding="UTF-8"?>

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd"
         updateCheck="true" monitoring="autodetect"
         dynamicConfig="true">

    <diskStore path="java.io.tmpdir"/>
    <transactionManagerLookup class="net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup"
                              properties="jndiName=java:/TransactionManager" propertySeparator=";"/>
    <cacheManagerEventListenerFactory class="" properties=""/>
    <terracottaConfig url="localhost:9510"/>

    <defaultCache
       maxElementsInMemory="0"
       eternal="false"
       overflowToDisk="true"
       timeToIdleSeconds="1200"
       timeToLiveSeconds="1200">
    </defaultCache>

    <cache name="rakutenItemSearchCache"
       maxElementsInMemory="10000"
       maxElementsOnDisk="1000"
       eternal="false"
       overflowToDisk="true"
       diskSpoolBufferSizeMB="20"
       timeToIdleSeconds="900"
       timeToLiveSeconds="900"
       memoryStoreEvictionPolicy="LFU"
       transactionalMode="off"
        />
</ehcache>

4,javaで実装。
もう面倒だからコピペさせてよ、という方向けにサンプルです。
まずはキャッシュロジッククラス。簡単に扱えるようにする為のクラスです。

public class CacheLogic {

    private static final Logger LOGGER = Logger.getLogger(CacheLogic.class);

    /**
     * キャッシュを追加する
     * @param conf 設定
     * @param cacheKey キー
     * @param obj
     */
    public void setCache(String conf, String cacheKey, Object obj) {
        if (obj == null) {
            return;
        }
        CacheManager manager = CacheManager.getInstance();
        if (!manager.cacheExists(conf)) {
            LOGGER.error("キャッシュ設定が見つかりませんでした。cacheName=" + conf);
            return;
        }
        Cache cache = manager.getCache(conf);
        cache.put(new Element(cacheKey, obj));
        LOGGER.info("キャッシュに登録しました。key=" + cacheKey);
    }

    /**
     * キャッシュを取得する
     * @param conf 設定
     * @param cacheKey キー
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T> T getCache(String conf, String cacheKey) {
        CacheManager manager = CacheManager.getInstance();
        if (!manager.cacheExists(conf)) {
            LOGGER.error("キャッシュ設定が見つかりませんでした。cacheName=" + conf);
            return null;
        }
        Cache cache = manager.getCache(conf);
        Element element = cache.get(cacheKey);
        if (element == null) {
            LOGGER.info("キャッシュが見つかりませんでした。key=" + cacheKey);
            return null;
        }
        LOGGER.info("キャッシュを取得しました。key=" + cacheKey);
        return (T) element.getValue();
    }
}

続いてキャッシュの呼び出し・登録です。

public class ItemSearchAction {

    @Resource
    protected CacheLogic cacheLogic;

    @Execute(validator = true, input = "index.jsp")
    public String index() {
        // キー名はURLを使用
        String cacheKey = itemSearchForm.queryString;
        ItemSearchResponseDto dto = cacheLogic.getCache("rakutenItemSearchCache", cacheKey);
        if (dto == null) {
            // キャッシュ無し(普通に検索する)
            dto = executeItemSearch(getItemSearchParameter());
            cacheLogic.setCache("rakutenItemSearchCache", cacheKey, dto);
        }
    }
}

引数のキャッシュのキー文字列は注意です。
以下のサンプルではURL中のQueryStringを使ってしまっていますが、
タイムスタンプ等がパラメータに含まれると、キャッシュの意味が無くなり、
キャッシュ数が多くなり、他のキャッシュを削除してしまう原因にもなります。

また、キャッシュの登録については注意が必要です。
キャッシュの登録処理はクローラは除外するのは必須です。
よくあるのが、クローラが大量にアクセスして、大量にキャッシュを量産してメモリを溢れさせるという
通り魔的な事をされるので、登録処理だけはUAを元にクローラを除外した方がいいです。
キャッシュの参照に関してはユーザもクローラも関係無いので、除外の必要はありません。


以下はGAE上でEHCacheを扱う方法を書いたトピックスです。
GAEJでEHCacheを動かす - 文系プログラマによるTIPSブログ

やさしいJava 第3版 (やさしいシリーズ)

やさしいJava 第3版 (やさしいシリーズ)