web-dev-qa-db-ja.com

アイテム/エンティティのコレクションを含むSpring Cache

キーのコレクションを渡すSpring Cacheを使用しており、戻り値はエンティティのリストです。リターンリストの各要素が対応するコードでキャッシュされることをキャッシングフレームワークに理解してもらいたい。現時点では、キーはリスト全体であるように見えます。その後の呼び出しでキーが欠落している場合、コレクション全体を再度リロードしようとします。

@Override
@Cacheable(value = "countries")
public List<Country> getAll(List<String>codes) {
    return countryDao.findAllInCodes(codes);
}

別の可能性は、戻り値がマップであるということです。同様に、以前に照会されたことのない項目のみを照会し、各項目をキーでキャッシュできるようにキャッシュを十分にインテリジェントにしたいです。

@Override
@Cacheable(value = "countries")
public Map<String,Country> getAllByCode(List<String>codes) {
    return countryDao.findAllInCodes(codes);
}

国クラスが次のようになっているとします:

class Country{
  String code; 
  String fullName;
  long id;

... // getters setters constructurs etc.. 
}

これはSpring Cacheで可能ですか?

16
Charbel

実際、 ​​Spring's Caching Abstraction でも可能ですが、すぐに使用できるわけではありません(OOTB)。基本的に、Springのキャッシュインフラストラクチャをカスタマイズする必要があります(以下でさらに説明します)

defaultにより、Springのキャッシングインフラストラクチャは、@Cacheableメソッドパラメータ引数全体をキャッシュの「キー」として使用します ここに 。もちろん、SpEL Expressionを使用するか、カスタムのKeyGenerator実装を使用して、キー解像度をカスタマイズすることもできます( こちら )。

それでも、はそうではありませんパラメータ引数のコレクションまたは配列を分割します@Cacheableメソッドの戻り値とともに、個々のキャッシュエントリ(配列/コレクションまたはマップに基づくキー/値のペア)へ。

そのためには、SpringのCacheManager(キャッシング戦略/プロバイダーに依存)およびCacheインターフェイスのカスタム実装が必要です。

注:皮肉なことに、これは私がほぼ同じ質問に最初に答えたのは3回目です。最初に here 、次に here 、そして今here、:-)。とにかく...

この投稿のために 私の例 (少し)を更新/クリーンアップしました。

私の例は拡張およびカスタマイズしますSpring Framework自体で提供される ConcurrentMapCacheManager に注意してください。

理論的には、Spring Data RedishereRedisののようなCacheManager実装を拡張/カスタマイズできます。 ( source )、またはPivotal GemFireのCacheManager in Spring Data GemFirehereソース )。 Pivotal GemFireのオープンソースバージョンはApache Geodeであり、対応するSpring Data Geodeプロジェクト、( CacheManagerのソース in Spring Data Geode、基本的にSD GemFireと同じ)。もちろん、この手法を他のキャッシングプロバイダーに適用できます... Hazelcast、Ehcacheなど。

ただし、作業の本質は、SpringのCache インターフェイスの カスタム実装 (または、より具体的には 基本クラス )によって処理されます。

とにかく、できれば my example から、アプリケーションのキャッシュ要件を満たすためにアプリケーションで何をする必要があるかを理解できるようになります。

さらに、Mapsの処理にも同じアプローチを適用できますが、これは演習として残しておきます;-)。

お役に立てれば!

乾杯、ジョン

16
John Blum

@CachePutとヘルパーメソッドを使用すると、次のように非常に簡単に実現できます。

public List<Country> getAllByCode(List<String>codes) {
    return countryDao.findAllInCodes(codes);
}

public void preloadCache(List<String>codes) {
    Map<String,Country> allCountries = getAllByCode(codes);
    for (Country country : allCountries) {
        cacheCountry(country);
    }
}

@CachePut
public Country cacheCountry(Country country) {
    return country
}

これにより、キャッシュに値が追加されるだけで、古い値は削除されません。新しい値を追加する前に、キャッシュエビクションを簡単に実行できます。

オプション2

次のように機能させる提案があります。

@CollectionCacheable
public List<Country> getAllByCode(List<String>codes) {    

見る :

せっかちな場合は、GitHubからコードを取得してローカルに統合します

0
Peter Szanto