【コラム】

Java API、使ってますか?

30 Javaアプリケーションにオブジェクトのキャッシュ機構を提供するJCache API

30/60

JSR 107: JCACHE - Java Temporary Caching API

Javaアプリケーション開発時に、繰り返し利用されるオブジェクトをキャッシュすることでパフォーマンスを劇的に向上させられる場合がある。「JSR 107: JCACHE - Java Temporary Caching API」は、そのような目的のための標準的なキャッシュ機構を提供するAPIだ。

JCacheは2005年にAPIのドラフトが公開されているが、それ以降目立った活動はなかった。しかし今年になって高性能なキャッシュライブラリであるEhcacheの開発者の一人、Greg Luck氏がスペックリードに加わり、再び標準化作業が進められるのではないかと期待されている。EhcacheはThe Apache Software License, Version 2.0のもとに公開されているオープンソースのキャッシュライブラリで、もともとJCacheとは独立したプロダクトだが、バージョン1.3よりJCache APIのドラフト仕様をサポートするようになった。

JCache APIのドラフトをサポートしたEhcacheを試す

JCache APIのドラフトはjava.net上のプロジェクトサイトにて公開されている。ただしこの内容には不完全な部分が多く、最終リリースまでに大きく変更される可能性が高いとGreg Luck氏は語っている。EhcaheのJCacheサポート機能はこの不完全なドラフトに基づいて実装されているため、現時点ではEhcacheで提供される機能と組み合わせて利用するのが現実的と言える。

Ehcacheはこのページより入手できる。JCache APIは1.3以降でサポートされており、本稿執筆時点での最新版はバージョン1.4.0 Beta。ダウンロードしたファイルを展開して、ehcache-1.4.0-beta.jar(1.4.0 Betaの場合)とlibディレクトリに含まれる各JARファイルをクラスパスに含めて利用すればよい。

Ehcacheでは、JCache APIの実装をnet.sf.jsr107cacheパッケージとして提供している(これは/lib/jsr107cache-1.0.jarに含まれる)。また、各インタフェースの実装クラスはnet.sf.ehcache.jcacheパッケージ以下に含まれている。Ehcacheが独自に提供するクラス群と名前が衝突しているので、使用の際には注意が必要。

まず、JCache APIで提供される機能のみでキャッシュ機構を利用してみる。キャッシュを作成する基本的な手順は以下のようになる。

  1. CacheManagerを取得する
  2. CacheManagerからCacheFactoryを取得する
  3. CacheFactoryからCacheオブジェクトを生成する…Cacheの設定はjava.util.Mapに格納する

CacheをCacheManagerに登録する

CacheインタフェースはMapインタフェースを継承しているため、キャッシュしたいオブジェクトはput()メソッドによってキーとセットで格納すればよい。逆にキャッシュからオブジェクトを取り出す場合には、getEntry()メソッドを用いてCacheEntry(これはMap.Entryの継承クラス)オブジェクトを取得する。なお、CacheManagerはgetInstance()メソッドを用いることで環境に唯一のインスタンスを取得できる。

実際にJCache APIを利用したプログラム例をリスト1に示す。ここではインターネットからロードしたImageIconオブジェクトをキャッシュに保存し、それを再度取得する例を示している。Cacheに対する設定内容についてはJCache APIのドラフトには詳細が記されていないため、CacheFactoryの実装クラスであるnet.sf.ehcache.jcache.JCacheFactoryクラスのドキュメントを参照のこと。

リスト1 CacheSample.java - JCache APIの使用例

package apisample.jcache;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.swing.ImageIcon;
import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheEntry;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheFactory;
import net.sf.jsr107cache.CacheManager;

public class CacheSample {
    public CacheSample() {
        // CacheManagerを取得
        CacheManager manager = CacheManager.getInstance();

        try {
            // CacheFactoryを取得
            CacheFactory cacheFactory = manager.getCacheFactory();

            // Cacheの設定をMapに書き込み、CacheFactoryからCacheを生成
            Map config = new HashMap();
            config.put("name", "sampleCache"); 
            config.put("maxElementsInMemory", "10");
            config.put("memoryStoreEvictionPolicy", "LFU"); // LFU,LRU,FIFOのどれか
            config.put("overflowToDisk", "true");
            config.put("eternal", "false");
            config.put("timeToLiveSeconds", "5");
            config.put("timeToIdleSeconds", "5");
            config.put("diskPersistent", "false");
            config.put("diskExpiryThreadIntervalSeconds", "120");

            Cache cache = cacheFactory.createCache(config);

            // CacheManagerにCacheを登録
            manager.registerCache("sampleCache", cache);
        } catch (CacheException ex) {
            ex.printStackTrace();
        }

        Cache cache = manager.getCache("sampleCache");
        try {
            // Cacheにオブジェクトを追加
            ImageIcon icon = new ImageIcon
                    (new URL("http://journal.mycom.co.jp/images/ci_mycomjournal.gif"));
            cache.put("image1", icon);
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }        
    }

    public static void main(String[] args) {
        CacheSample sample = new CacheSample();

        // CacheManagerからCacheを取得し、オブジェクトを取り出す
        CacheManager singletonManager = CacheManager.getInstance();
        Cache cache = singletonManager.getCache("sampleCache");
        CacheEntry entry = cache.getCacheEntry("image1");
        ImageIcon value = (ImageIcon)entry.getValue();
        System.out.println(value);
    }
}

続いて、Ehcacheの提供するCacheManager(JCache APIのものと区別するため、ここではパッケージ名も含めてnet.sf.ehcache.CacheManagerと記述する)を利用して、JCache APIのCacheを管理する例を紹介しよう。EhcaheではCacheインタフェースの実装クラスとしてnet.sf.ehcache.jcache.JCacheというクラスが用意されている。JCacheオブジェクトはEhcacheで通常利用するnet.sf.ehcache.Cacheオブジェクト(JCache APIのものではないので注意)を元に生成することができる。

net.sf.ehcache.Cacheオブジェクトを生成する方法はいくつかあるが、もっとも簡単なのはnet.sf.ehcache.CacheManagerのaddCache()メソッドによってデフォルト設定のキャッシュを作ってしまうことだ。なお、net.sf.ehcache.CacheManagerはcreate()メソッドによって環境に唯一のマネージャを生成できる。すでに生成済みのマネージャを取得する場合はgetInstance()メソッドを使用する。

実際のプログラム例をリスト2に示す。現時点ではJCache APIのドラフトで定義されているキャッシュ機構よりも、Ehcacheに実装されているものの方が完成度が高いため、こちらの例の方がより現実的と言えるだろう。

リスト2 CacheSampleWithEhcache.java

package apisample.jcache;

import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.ImageIcon;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.jcache.JCache;
import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheEntry;

public class CacheSampleWithEhcache {
    public CacheSampleWithEhcache() {
        // EhcacheのCacheManagerを作成してEhcaheを追加
        CacheManager manager = CacheManager.create();
        manager.addCache("sampleCache");

        // EhcacheからJCacheを作成
        Cache cache = new JCache(manager.getCache("sampleCache"), null);
        try {
            // JCacheにオブジェクトを追加
            ImageIcon icon = new ImageIcon
                    (new URL("http://journal.mycom.co.jp/images/ci_mycomjournal.gif"));
            cache.put("image1", icon);
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        CacheSampleWithEhcache sample = new CacheSampleWithEhcache();

        // CacheManagerからJCacheを取得し、オブジェクトを取り出す
        CacheManager singletonManager = CacheManager.getInstance();
        Cache cache = singletonManager.getJCache("sampleCache");
        CacheEntry entry = cache.getCacheEntry("image1");
        ImageIcon value = (ImageIcon)entry.getValue();
        System.out.println(value);
    }
}

Greg Luck氏によれば、今後はEhcacheによる成果も取り入れながらJCache APIの詳細を再検討していくとのことである。なお、Ehcache自身は単純なキャッシュ機構の実装だけでなく、さまざまなケースに応じた機能を提供している。また、Ehcacheを元にさまざまなキャッシュパターンを実装した「Ehcache Constructs」というプロダクトもある。JCache APIの登場が待てない開発者は、Ehcacheの利用を検討してみるのもいいだろう。

30/60

インデックス

連載目次
第60回 どうなる? 今後のJavaプラットフォーム(Java SE編)
第59回 どうなる? 今後のJavaプラットフォーム(Java EE編)
第58回 Java SE 7の要注目機能"クロージャ"はどうなるのか その6
第57回 Java SE 7の要注目機能"クロージャ"はどうなるのか その5
第56回 Java SE 7の要注目機能"クロージャ"はどうなるのか その4
第55回 Java SE 7の要注目機能"クロージャ"はどうなるのか その3
第54回 Java SE 7の要注目機能"クロージャ"はどうなるのか その2
第53回 Java SE 7の要注目機能"クロージャ"はどうなるのか
第52回 Early Draftが公開されたJSF 2.0
第51回 EJBから独立したJava Persistence 2.0
第50回 モバイルJavaの新しい潮流となるか - MSA 2.0のドラフト公開
第49回 やっぱり基本はServlet - Servlet 3.0のEarly Draftを読む
第48回 JOGLで3Dプログラミング その4
第47回 JOGLで3Dプログラミング その3
第46回 JOGLで3Dプログラミング その2
第45回 JOGLで3Dプログラミング
第44回 JARファイルを効率的にネットワーク転送するためのPack200形式
第43回 Early Draftで把握するEJB 3.1の新機能
第42回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その2
第41回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その1
第40回 リソースアダプタによる接続の仕組み
第39回 JCAを利用したシステム間接続
第38回 Java EEと外部システムの接続性を支えるJCAがバージョンアップ
第37回 Javaのモジュラリティ強化を担う"スーパーパッケージ"とは
第36回 JSR 308対応のコンパイラを試す
第35回 公開されたJSR 308のEarly Draftを検証する
第34回 スクリプト言語とJavaを結びつけるJSR 223
第33回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その2
第32回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その1
第31回 Javaの文法がそのまま使えるスクリプト言語"BeanShell"
第30回 Javaアプリケーションにオブジェクトのキャッシュ機構を提供するJCache API
第29回 Javaアプリケーションからのリソース管理を可能にするJSR 284
第28回 XMLデータソースへの問い合わせはJSR 225で
第27回 Portlet Specification 2.0をもっと手軽に利用する
第26回 次期Javaポートレット仕様となるJSR 286
第25回 JSFとポートレットをつなげるJSR 301
第24回 Webサービス向けのポートレット仕様「WSRP」
第23回 高い相互運用性を実現するポートレットAPI - JSR 168
第22回 Java EE環境でタスクのスケジューリングを可能にするJSR 236
第21回 Java EE環境でのスレッドプログラミングを可能にするJSR 237
第20回 音声認識/合成のためのAPI - Java Speech APIとJSR 113
第19回 JSR 291でJavaプラットフォームにダイナミックコンポーネントモデルを導入
第18回 JAX-RSで簡単RESTful - JSR 311
第17回 待望のServlet 3.0がJSRに登場 - JSR 315
第16回 アノテーションを使ってバグ退治 - JSR 305
第15回 アノテーションをさらに広い範囲で利用可能にするJSR 308
第14回 Webアプリケーション開発の要となるか - JSF 2.0がJSRに登場
第13回 Webサービス経由でのJMX Agentへの接続を可能にするJSR 262
第12回 Javaアプリケーションのモジュール化をサポートするJava Module System
第11回 "NIO.2"がやってきた - JSR 203: More New I/O APIs for the Java Platform
第10回 JSR 295: Beans Bindingの参照実装を試す
第9回 けっこう便利! 単位を扱うAPI -- JSR 275: Units Specification
第8回 アノテーションでバリデーション - JSR 303: Bean Validator
第7回 Swing開発の救世主となるか - Swing Application Framework
第6回 JavaBeansのプロパティを同期させるバインディングAPI
第5回 誰よりも早く"Java SE 7"を睨む
第4回 日時情報の取り扱いを改善する JSR 310: Date and Time API
第3回 古いAPIも進化している!? - JSR 919: JavaMail 1.4
第2回 JSR 1 リアルタイムJava仕様
第1回 JCPによって進められるJava関連技術の標準化

もっと見る

提供:マイナビ

会員登録はこちら

大学・大学院・短大・専門学生向けの就職情報サイト「マイナビ2010」「マイナビ2009」に今すぐ登録しよう!  大手企業からベンチャー企業までの約13,000社の企業情報を公開、エントリーが可能です。2010年卒予定の方は「マイナビ2010」に、2009年卒予定の方は「マイナビ2009」に登録してください。

毎日コミュニケーションズはプライバシーマークを取得しています。



人気記事

一覧

イチオシ記事

新着記事