fine, later feeling

晴れのち気分

PlayのCacheAPIをサブプロジェクトで使いたい

ある程度アプリケーションが大きくなってくるとサブプロジェクトを作ってプロジェクト分割したくなる時があります。

例えばサブプロジェクトでplayのCacheAPIを利用したいと思っても残念ながらplayのCacheAPIはplay.api.Applicationに依存しているため、直接使うことができません。

playアプリケーション起動時にplay.api.cache.Cacheの実装を渡してしまえばサブプロジェクトでもplayのCacheAPIを利用することができます。

インターフェースを定義します。

trait Cache {
  def get(key: String): Option[Any]
  def set(key : String, value : Any, expiration : Int): Unit
  def set(key: String, value: Any, expiration: scala.concurrent.duration.Duration): Unit
  def remove(key: String): Unit
}

Cacheの実装を呼び出すクラスを定義します。

class CacheService {
  private var cache: Cache = null
  def setCacheImpl(src: Cache): Unit = {
    cache = src
  }

  def get(key: String): Option[Any] = {
    if (cache == null) {
      None
    } else {
      cache.get(key)
    }
  }

  def set(key: String, value: Any, expiration: Int): Unit = {
    cache.set(key, value, expiration)
  }

  def set(key: String, value: Any, expiration: Duration): Unit = {
    cache.set(key, value, expiration)
  }

  def remove(key: String): Unit = {
    cache.remove(key)
  }
}

object CacheService extends CacheService

GlobalオブジェクトのonStart()でアプリケーション起動時にCacheの実装を注入します。

  object PlayCacheImpl extends Cache {
    override def get(key: String): Option[Any] = {
      play.api.cache.Cache.get(key)
    }

    override def set(key: String, value: Any, expiration: Int): Unit = {
      play.api.cache.Cache.set(key, value, expiration)
    }

    override def set(key: String, value: Any, expiration: Duration): Unit = {
      play.api.cache.Cache.set(key, value, expiration)
    }

    override def remove(key: String): Unit = {
      play.api.cache.Cache.remove(key)
    }
  }
  CacheService.setCacheImpl(PlayCacheImpl)

実際の使い方は以下のように呼び出せます。

val cacheMap = CacheService.get("キャッシュキー")

こうすることでPlay起動時に実装を注入し、サブプロジェクトでもPlayのCacheを使えるようになります。

他にもHTTPクライアントであるWSplay-mailerなど使いまわしたいけどplay.api.Applicationに依存するAPIがいくつもあるので、無闇やたらに使うことは避けたほうがいいと思います。