【问题标题】:@Caching With Multiple Keys@使用多个键缓存
【发布时间】:2012-11-03 02:53:56
【问题描述】:

我有一个接受 DTO 并返回一些结果的服务:

@Override
public int foo(Bar bar) {
    ....
}

条形如下(简化):

public class Bar {
    public int id;
    public String name;
    public String baz;

    @Override
    public int hashCode() {
        //this is already being defined for something else
        ...
    }

    @Override
    public boolean equals(Object o) {
        //this is already being defined for something else
        ...
    }
}

我想在 foo 方法上使用 @Cacheable;但是,我想对 id 和 name 属性进行哈希处理,而不是 baz。有没有办法做到这一点?

【问题讨论】:

标签: java spring caching methods


【解决方案1】:

你也可以使用这种方法

@Override
@Cacheable(key="{#bar.name, #bar.id}")
public int foo(Bar bar) {
    ....
}

建议不要使用hashcode作为key @Cacheable key on multiple method arguments

【讨论】:

  • 但是当我使用这种方法时,它会抛出java.lang.ClassCastException: Invalid key type, expected : org.springframework.cache.interceptor.SimpleKey but was : java.util.ArrayList。我该如何克服这个问题?
【解决方案2】:

是的,您可以按照以下方式使用 Spring-EL 表达式来指定:

@Override
@Cacheable(key="#bar.name.concat('-').concat(#bar.id)")
public int foo(Bar bar) {
    ....
}

或在 bar 上定义一个修改后的 hashCode 并调用它:

@Override
@Cacheable(key="#bar.hashCodeWithIdName")
public int foo(Bar bar) {
    ....
}

【讨论】:

  • 如果 '-' 是公共静态最终字符串数据。我该怎么办?
【解决方案3】:

你可以使用 Spring SimpleKey 类

@Cacheable(value = "barCache", key = "new org.springframework.cache.interceptor.SimpleKey(#bar.id, #bar.name)")

【讨论】:

  • 这适用,但为什么@vsingh 解决方案会给我java.lang.ClassCastException: Invalid key type, expected : org.springframework.cache.interceptor.SimpleKey but was : java.util.ArrayList 异常?
  • 但是为什么需要key = "new org.springframework.cache.interceptor.SimpleKey(#bar.id, #bar.name)"而不是key = "{#bar.id, #bar.name}"
【解决方案4】:

@Biju 和@vsingh 的两个答案都是正确的;但如果您尝试缓存的Bar 对象很复杂,或者foo 方法包含大量参数,使用SpEL 可能不是生成密钥的最理想解决方案,我想再添加一个替代方案。

您也可以考虑keyGenerator

例子:

@Override
@Cacheable(value="barCahceKey", keyGenerator="barKeyGenerator")
public int foo(Bar bar) {
  ....
}

@Component
public class BarKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object o, Method method, Object... objects) {
      // TODO logic to generate unique key
      return "Bar_Key_Generator_With_Params_etc";
    }
}

通过这种方法,您可以完全灵活地构建密钥。

KeyGenerator API

【讨论】:

  • 自定义 keyGenerator 只允许创建 1 个密钥。从 KeyGenerator 获得多个密钥怎么样?此 KeyGenerator 仅返回对象而不是对象数组。所以,我猜自定义 KeyGenerator 不能用于多个密钥生成。
【解决方案5】:

来自同一个Object的key,可以使用object.hashCode(),这样就不需要一个个的指定key

@Override
@Cacheable(key="#bar.hashCode()")
public int foo(Bar bar) {
    ....
}

或者如果你有一个对象和另一个键

@Override
@Cacheable(key="{#bar.hashCode(), #anotherKey}")
public int foo(Bar bar) {
    ....
}

我认为这是一个更好的解决方案。

【讨论】:

  • 哈希码很危险,因为它们不能保证是唯一的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
  • 2018-06-15
  • 2016-09-10
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多