S2Click 1.0.3をリリースしました。
このバージョンはS2Click 1.0.2でClickのJARファイル内に含まれるリソースの自動デプロイに関する問題を修正したバージョンになります。
S2Click 1.0.3をリリースしました。
このバージョンはS2Click 1.0.2でClickのJARファイル内に含まれるリソースの自動デプロイに関する問題を修正したバージョンになります。
Seasar2徹底入門で紹介しようと思い、途中まで原稿も書いていたS2Cachingについてですが、せっかくなのでこのブログで紹介しておこうと思います。
S2CachingはAOPで任意のメソッドの呼び出しをインターセプトし、戻り値をキャッシュするための機能を提供します。バックエンドのキャッシュライブラリとしてEhcacheを使用しています。
S2Cachingを使うには以下のURLからs2caching-0.1-SNAPSHOT.jarをダウンロードし、クラスパスに追加します。
また、その他にEhcacheの動作に必要なJARファイルと、S2Cachingが内部的に使用しているCommons-Langもクラスパスに追加する必要があります。Ehcacheは以下のURLからダウンロードすることができます。
diconファイルに以下のようにインターセプターを登録します。
<component name="cacheManager" class="net.sf.ehcache.CacheManager"> @net.sf.ehcache.CacheManager@getInstance() <destroyMethod name="shutdown" /> </component> <component class="org.seasar.caching.interceptor.CallCacheInterceptor" name="cacheInterceptor"> <arg>cacheManager</arg> <arg>"cache-01"</arg> </component>
また、Ehcacheの設定を行うためにehcache.xmlという設定ファイルをクラスパスルートに作成する必要があります。ehcache.xmlの例を以下に示します。defaultCacheだけ定義していますが、キャッシュごとに設定を変えたい場合は別々に定義することもできるみたいです。
<?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"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" statistics="false" /> </ehcache>
一応必要最低限の設定にしたつもりですが、Ehcacheは使ったことがないのでこの設定で正しいのかどうかはわかりません。ehcache.xmlの詳細な設定については以下のURLを参照してください(機会があれば翻訳してみたいです)。
長くなりましたが以上で準備は完了です。cacheInterceptorを任意のメソッドに適用することでメソッドの戻り値をキャッシュすることができます。ただし、戻り値をキャッシュ可能なメソッドには以下の制約があります。
S2Cachingはキャッシュされた値を返却する場合、シリアライズによって複製したオブジェクトを返却します。このため、返却されたオブジェクトに対して破壊的な操作を行ってもキャッシュされたエントリには影響ありません(逆にキャッシュされたオブジェクトを変更することはできません)。
また、S2Cachingはキャッシュのキーとして以下を用います。つまり、同一のメソッドに対し、引数の値が一致した場合にキャッシュされたエントリが返却されるということになります。このため、引数のパターンが多いメソッドに対して適用してもキャッシュ効率は非常に悪いので注意してください。
S2Cachingではキャッシュを削除するための機能を提供していません。キャッシュエントリを削除するにはEhcacheのAPIを直接呼び出す必要があります。
CacheManager cm = SingletonS2Container.getComponent(CacheManager.class); // 全部削除 cm.removeAll(); // キャッシュを指定して削除 cm.getCache("cache-01").removeAll()
全部もしくはキャッシュ単位でしか削除できないため(キーを指定して1エントリずつ削除することももちろん可能ですが、キーはS2caching側で自動生成しているのであまり現実的ではないかと…)、キャッシュの削除タイミングが異なる場合はあらかじめ削除タイミングにあわせてキャッシュと、それに対応するインターセプターを複数定義しておく必要があります。それでもそれほど細かい制御はできないですね。
個人的な感覚としては、特に削除に関して大雑把な制御しかできないため、実際のプロジェクトで利用するには用途が限られるのではないかと思います。アプリケーションスコープに格納するような、変更のないマスタデータのキャッシュなどであれば使えるのではないでしょうか。
2007年で開発が止まっているのも気になりますが、Seasar 2.3時代に作られたプロダクトであるためか、アノテーションでのインターセプターの適用などに対応していないなど、使いにくい部分も見受けられます。使う場合は自分で使いやすいよう手を入れて使うのがよいかもしれません。
あと、S2Cachingというよりも、むしろEhcacheの設定や挙動をしっかりと把握しておくことが大切です。通常のライブラリと違ってキャッシュライブラリはメモリとディスクの使い分け、最大キャッシュ数やアルゴリズムやクラスタリングなどかなり細かく設定を行うことができます。ehcache.xmlで設定できる内容をきちんと理解して適切に設定を行う必要があります。
public class Example { private static <T> T hoge(Object obj){ return (T) obj; } public static <T> T hage(Object obj){ return hoge(obj); } }
みたいな感じで書くとEclipseだとOKだけど、Maven(というかjavac)でコンパイルすると下のメソッドから上のメソッドの戻り値をreturnしているところでこんな感じで怒られます。
型パラメータ <T>T を判別できません; 型変数 T (上限 T,java.lang.Object) の固有の最大インスタンスが存在しません。
こんなときは慌てず騒がずこんな感じで。
public static <T> T hage(Object obj){ return Example.<T> hoge(obj); }
かっこ悪いけど素直にキャストするのもありかも。
public static <T> T hage(Object obj){ return (T) hoge(obj); }