簡體   English   中英

如何在Cacheable注釋中使用該鍵

[英]How do I use the key, in a condition in Cacheable annotation

我正在使用@cacheable注釋來緩存函數的結果。 我有3個不同的緩存,每個緩存的關鍵是當前登錄用戶的用戶ID與方法中的參數連接。 在某個事件中,我想要驅逐所有具有以該特定用戶ID開頭的密鑰的緩存條目。 例如 :

@Cacheable(value = "testCache1", key = "'abcdef'")

我想緩存evict注釋是這樣的:

@CacheEvict(value = "getSimilarVendors", condition = "key.startsWith('abc')")

但是當我嘗試實現它時,它給了我一個錯誤:

Property or field 'key' cannot be found on object of type'org.springframework.cache.interceptor.CacheExpressionRootObject' - maybe not      public?

實現這個的正確方法是什么?

所有Spring Cache注釋(即@Cacheable@CacheEvict等)都在每個操作的1個緩存條目上工作。 @CacheEvict確實支持清除整個緩存(使用allEntries屬性,但是在這種情況下忽略了密鑰),但它沒有選擇性(有能力)根據單個操作中的密鑰模式清除部分條目集描述。

這背后的主要原因是Spring Cache接口抽象本身,其中evict(key:Object)方法采用單個鍵參數。 但從技術上講,它實際上取決於底層的Cache實現(例如GemfireCache ),它需要支持驅逐所有密鑰與特定模式匹配的條目,這通常不是大多數緩存的情況(例如,當然不適用於GemFire,以及不適用於Google Guava Cache;請參閱此處此處 。)

這並不是說你絕對無法實現自己的目標。 它不是開箱即用的東西。

有趣的是,減去你的方法的一些技術問題,就是你的條件達到了你想要的......只有當密鑰滿足條件時才會出現緩存驅逐。 但是,@ CacheEvict注釋方法只是缺少“鍵”,因此錯誤。 所以,像下面這樣的東西會滿足你的條件下的SpEL ......

@CacheEvict(condition = "#key.startsWith('abc')")
public void someMethod(String key) {
  ...
}

但是,在這種情況下,您必須將鍵指定為參數。 但是,您不需要特定的鍵,您需要一個匹配多個鍵的模式。 所以,放棄條件,只是使用......

@CacheEvict
public void someMethod(String keyPattern) {
  ...
}

舉例來說,使用Guava作為緩存提供程序,您現在需要提供擴展GuavaCache的“自定義”實現。

public class CustomGuavaCache extends org.springframework.cache.guava.GuavaCache {

  protected boolean isMatch(String key, String pattern) {
    ...
  }

  protected boolean isPattern(String key) {
    ...
  }

  @Override
  public void evict(Object key) {
    if (key instanceof String && isPattern(key.toString()))) {
        Map<String, Object> entries = this.cache.asMap();
        Set<String> matchingKeys = new HashSet<>(entries.size());
        for (String actualKey : entries.keySet()) {
          if (isMatch(actualKey, key.toString()) {
            matchingKeys.add(actualKey);
          }
        }
        this.cache.invalidateAll(matchingKeys);
    }
    else {
      this.cache.invalidate(key);
    }
  }
}

現在只需擴展GuavaCacheManager即可插入“自定義” GuavaCacheCustomGuavaCache )...

public class CustomGuavaCacheManager extends org.springframework.cache.guava.GuavaCacheManager {

  @Override
  protected Cache createGuavaCache(String name) {
    return new CustomGuavaCache(name, createNativeGuavaCache(name), isAllowNullValues());
  }
}

這種方法利用了Guava的Cache的 invalidateAll(keys:Iterable)方法。 當然,您可以使用Java的Regex支持對所需的鍵執行“匹配”,以便在isMatch(key, pattern)方法中逐出。

所以,我沒有測試過這個,但是這個(或類似的東西)應該達到(幾乎)你想要的東西(手指交叉;-)

希望這可以幫助!

干杯,約翰

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM