使ったもの
- JCache API 1.0.0
- Ehcache 3
- Guice
// Groovy Version: 2.4.5 JVM: 1.8.0_77 Vendor: Oracle Corporation OS: Mac OS X
@Grab('javax.cache:cache-api:1.0.0')
@Grab('org.ehcache:ehcache:3.2.0')
@Grab('org.jsr107.ri:cache-annotations-ri-guice:1.0.0')
@Grab('com.google.inject:guice:4.1.0')
import com.google.inject.AbstractModule
import com.google.inject.Guice
import com.google.inject.Injector
import org.jsr107.ri.annotations.guice.module.CacheAnnotationsModule
import javax.cache.CacheManager
import javax.cache.Caching
import javax.cache.annotation.CacheDefaults
import javax.cache.annotation.CacheResult
import javax.cache.configuration.Configuration
import javax.cache.configuration.MutableConfiguration
import javax.cache.expiry.AccessedExpiryPolicy
import javax.cache.expiry.Duration
import javax.cache.spi.CachingProvider
import java.text.SimpleDateFormat
import java.util.concurrent.TimeUnit
@CacheDefaults(cacheName = 'simpleCache')
class Sample {
@CacheResult
String hello() {
new SimpleDateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(new Date())
}
}
CachingProvider cachingProvider = Caching.getCachingProvider();
CacheManager cacheManager = cachingProvider.getCacheManager();
Configuration<Object, Object> config =
new MutableConfiguration<Object, Object>()
.setTypes(Object.class, Object.class)
// キャッシュの有効期間は1秒
.setExpiryPolicyFactory(AccessedExpiryPolicy.factoryOf(new Duration(TimeUnit.SECONDS, 1)));
cacheManager.createCache('simpleCache', config)
Injector injector = Guice.createInjector(new CacheAnnotationsModule())
Sample sample = injector.getInstance(Sample.class);
println sample.hello()
println sample.hello()
println sample.hello()
println sample.hello()
println sample.hello()
// ↑は全て同じ時刻が出力されること
TimeUnit.SECONDS.sleep(1)
// キャッシュ切れで取得し直して上とは違う時刻が出力されること
println sample.hello()
結果
2016-12-24 14:04:27.284
2016-12-24 14:04:27.284
2016-12-24 14:04:27.284
2016-12-24 14:04:27.284
2016-12-24 14:04:27.284
2016-12-24 14:04:28.312 # 結果がここだけ上と違う。想定通り
CDIとかを使わないでメソッドの結果をキャッシュするのをサクッと試そうとしただけなのに、20時間ほど要してしまった。。
最初の想定としては、
- JCache APIと実装を依存性に追加
- POJOのキャッシュしたいメソッドに
@javax.cache.annotation.CacheResult
付ける
くらいで出来るだろうと思っていたが、全然違った。
実際は、
- JCache APIと実装を依存性に追加
- CDIやSpring Framework以外で使うためにはGuiceしか選択肢がなさそうなのでGuiceを依存性に追加
- Guice用の
cache-annotations-ri
を依存性に追加 - POJOのキャッシュしたいメソッドに
@javax.cache.annotation.CacheResult
付ける -
javax.cache.annotation.CacheResolverFactory
やJCacheのInterceptorの設定をする
というように、かなり込み入ったことが必要だった。
よもやま
keyとvalueを共にjava.lang.Object
で利用しているが、これはorg.jsr107.ri.annotations.DefaultCacheResolverFactory#getCacheResolver
がjavax.cache.CacheManager#getCache(java.lang.String)
を中で呼んでいてEhcacheの実装を見たところ、key, valueがObject
になっていないとダメなことが分かったため。
javax.cache.CacheManager#getCache(java.lang.String, java.lang.Class<K>, java.lang.Class<V>)
を呼ぶようにすれば、任意の型で扱えるはずなので、CacheResolverFactory
を自分で実装すれば変えられそう。とりあえず今回はさっさと動かすことを重視してkey, valueをObject
にした。
Interceptorの設定は完全にFathomというフレームワークのコードを利用している。ありがたや。。今度このフレームワーク自体も試してみたい。
[追記] ↑ @kazuhira_r さんのご指摘により、org.jsr107.ri.annotations.guice.module.CacheAnnotationsModule
を使うようにしてコード量削減。
所感
JCacheはBean Validationのように雰囲気とノリと勢いで試せるものではなかった。ドキュメントのサンプルもイマイチ役に立たなかったし。
参考
- https://docs.google.com/document/d/1MZQstO9GJo_MUMy5iD5sxCrstunnQ1f85ekCng8LcqM/edit?usp=sharing
- http://www.ehcache.org
- http://d.hatena.ne.jp/Kazuhira/20131204/1386163253
- http://d.hatena.ne.jp/Kazuhira/20150709/1436452506
- https://github.com/gitblit/fathom/blob/master/fathom-jcache/src/main/java/fathom/jcache/JCacheModule.java