当前位置: 首页 > 面试题库 >

在可缓存注释中的情况下,如何使用密钥

艾焱
2023-03-14
问题内容

我正在使用@cacheable注解缓存函数的结果。我有3个不同的缓存,每个缓存的关键是当前登录的用户的用户ID,该用户ID与方法中的参数连接在一起。在某个事件中,我想逐出所有具有以该特定用户ID开头的键的缓存条目。例如

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

我希望缓存逐出注释为:

@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)方法采用单个key参数。但是从技术上讲,它实际上取决于基础的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即可插入“html" target="_blank">自定义”
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)方法内逐出的所需键执行“匹配” 。

因此,我尚未对此进行测试,但是这种(或类似方法)应该(几乎)实现您想要的(手指交叉;-)

希望这可以帮助!

干杯,约翰



 类似资料:
  • 我有一个简单的Quarkus资源: 我试图将实例注入到我的资源中,但是我得到了一个。但是,如果我在上使用注释,那么一切都很好。是否有一种方法可以在不使用注释的情况下将类注入到我的资源中?换句话说,是否有一种方法可以使Quakus容器可以发现而不直接注释该类? 编辑:查看CDI文档,似乎可以使用带有注释的方法手动注册bean。但是,我不清楚哪个类应该包含带注释的方法) 另一个选择是使用Jandex索

  • 我将guava jar文件添加到类路径中,但我的IDE(eclipse)说: Nullable无法解析为类型 但如果我ctrl+单击Nullable,我会看到蓝色下划线,然后看到下划线:

  • 我目前需要一种使用AES-128对称加密对字符串加密和字节数组解密的方法,使用C#。我找不到办法,但也许我错过了什么。

  • 我试图了解DI在我们的代码库(Kotlin)中是如何使用的。我们正在使用googleguice进行依赖注入。 下面是一个示例类: 在模块类中: DepB类别: 据我所知,对于用< code>@Inject注释的变量,Google Guice会使用模块类来解决这些依赖关系。所以< code>DepA对象的注入方式是有意义的。 但是呢?我们如何能够在不指定任何位置的情况下注入DepB?

  • 我正在使用Spring 4.1.4和Ehcache 2.9并使用注释进行缓存。 我注意到,每个具有带有此注释的方法的公共类都必须在 谢谢