Scala:メソッド実行結果のキャッシュ

メソッドの実行結果をキャッシュすることが必要になる場合があります。 Javaの可能な解決策の1つをここで説明します 。 EHCache、呼び出しをインターセプトするためのSpring AOP、少しのコード:原則として、すべては簡単です。



私には、scalaのよりエレガントなソリューションを検討してください。



問題をより具体的に定式化します。 ミックスインを作成する必要があります。サービス実装に追加する場合、メソッド実行の結果のキャッシュを次のように追加できます。



final val CACHE_FIRST_USER_CREATED = "firstUserCreated" <br>

def isFirstUserCreated : Boolean = cache (<br>

{userDAO.getCount>0} withKey CACHE_FIRST_USER_CREATED forever<br>

)<br>









キャッシングオプションを定義する簡単なDSLから始めましょう。 以下を含むキャッシュオプションを記述するクラスが必要です。



class CacheOptions [T] (fn: =>T ) {<br>

var time = - 1 <br>

var key: String = "key" <br>

}<br>







forever、expirationTime、withKeyメソッド、このクラスのオブジェクトを埋めるための関数のデフォルト変換、および名前で渡された値fnを計算する_execFnメソッドを定義します。



class CacheOptions [T] (fn: =>T ) {<br>

var time = - 1 <br>

var key: String = "key" <br>

def _execFn : T = fn<br>

def forever = { this .time= - 1 ; this }<br>

def expirationTime (time: Int ) = { this .time=time; this }<br>

def withKey (key: String ) = { this .key=key; this }<br>

}<br>

<br>

implicit def fn2co [T] (fn: =>T ) = new CacheOptions [T] (fn)<br>

<br>







したがって、次の形式の式:

{ "lazy value" } withKey "mykey" expirationTime 30000<br>







満たされた時間、キー、およびfnフィールドを持つCacheOptions [String]オブジェクトを返します。



キャッシングに直接行きましょう。 最初に述べた記事では、EHCacheを使用して結果をキャッシュします。 同じことをすることを妨げるものは何もありませんが、簡単にするために、単純なConcurrentHashMapでキャッシュ結果を示します。



したがって、実際にはキャッシュメソッド:

private val cache = new ConcurrentHashMap [String,CacheRecord] <br>

<br>

def cache [T] (co: CacheOptions[T] ): T = {<br>

val timestamp = System.currentTimeMillis()<br>

val cr = cache.get(co.key)<br>

(cr== null ) match {<br>

case true => refresh(timestamp,co)<br>

case false => <br>

if (co.time> 0 && (timestamp-cr.timestamp)>co.time) <br>

refresh(timestamp,co) <br>

else <br>

cr.obj.asInstanceOf[ T ]<br>

}<br>

}<br>

<br>

private def refresh [T] (timestamp: Long , co: CacheOptions[T] ): T = {<br>

val cr = new CacheRecord (timestamp, co._execFn.asInstanceOf[ AnyRef ])<br>

cache.put(co.key, cr)<br>

cr.obj.asInstanceOf[ T ]<br>

}<br>

<br>







スペース技術なし-キャッシュからの選択、レコードのタイムスタンプのチェック、必要に応じて実行およびキャッシュ。



キャッシュからエントリを強制的に除外する簡単なメソッドを追加します。

def evict (key: String ): Unit = cache.remove(key)<br>







できた!



マイナス、スプリングaopの使用と比較して-入力パラメーターに応じて、キー作成手順を記述する必要があります(スプリングaopの決定では、これは自動的に行われます)。 長所-シンプルさ、レコードの削除を強制する機能



例として、ConcurrentHashMapでキャッシュを示しましたが、このソリューションの欠点は、EHCacheの使用と比較して明らかです-キャッシュ内のエントリ数を制限し、エントリを削除する戦略を決定する方法はありません。返される値が不変であることを確認する必要があります。キャッシュにあります。 ただし、これらの問題はすべて、この特性をEHCacheまたは他のライブラリを使用するように切り替えることで回避できます。 これは5分です。




All Articles