简体   繁体   English

多个方法参数上的@Cacheable 键

[英]@Cacheable key on multiple method arguments

From the spring documentation :弹簧文档

@Cacheable(value="bookCache", key="isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

How can I specify @Cachable to use isbn and checkWarehouse as key?如何指定@Cachable使用isbncheckWarehouse作为键?

Update : Current Spring cache implementation uses all method parameters as the cache key if not specified otherwise.更新:如果没有另外指定,当前的 Spring 缓存实现使用所有方法参数作为缓存键。 If you want to use selected keys, refer to Arjan's answer which uses SpEL list {#isbn, #includeUsed} which is the simplest way to create unique keys.如果您想使用选定的键,请参阅Arjan 的答案,它使用 SpEL 列表{#isbn, #includeUsed} ,这是创建唯一键的最简单方法。

From Spring Documentation来自Spring 文档

The default key generation strategy changed with the release of Spring 4.0.默认的密钥生成策略随着 Spring 4.0 的发布而改变。 Earlier versions of Spring used a key generation strategy that, for multiple key parameters, only considered the hashCode() of parameters and not equals(); Spring的早期版本使用了一种密钥生成策略,对于多个关键参数,只考虑参数的hashCode()而不考虑equals(); this could cause unexpected key collisions (see SPR-10237 for background).这可能会导致意外的密钥冲突(有关背景信息,请参阅 SPR-10237)。 The new 'SimpleKeyGenerator' uses a compound key for such scenarios.新的“SimpleKeyGenerator”在此类场景中使用复合键。

Before Spring 4.0 Spring 4.0 之前

I suggest you to concat the values of the parameters in Spel expression with something like key="#checkWarehouse.toString() + #isbn.toString()") , I believe this should work as org.springframework.cache.interceptor.ExpressionEvaluator returns Object, which is later used as the key so you don't have to provide an int in your SPEL expression.我建议你用key="#checkWarehouse.toString() + #isbn.toString()")类的东西连接 Spel 表达式中参数的值,我相信这应该可以作为 org.springframework.cache.interceptor.ExpressionEvaluator返回 Object,它稍后用作键,因此您不必在 SPEL 表达式中提供int

As for the hash code with a high collision probability - you can't use it as the key.至于碰撞概率高的哈希码——你不能用它作为密钥。

Someone in this thread has suggested to use T(java.util.Objects).hash(#p0,#p1, #p2) but it WILL NOT WORK and this approach is easy to break, for example I've used the data from SPR-9377 :这个线程中有人建议使用T(java.util.Objects).hash(#p0,#p1, #p2)但它不会工作,而且这种方法很容易被破坏,例如我使用了来自SPR-9377

    System.out.println( Objects.hash("someisbn", new Integer(109), new Integer(434)));
    System.out.println( Objects.hash("someisbn", new Integer(110), new Integer(403)));

Both lines print -636517714 on my environment.这两行都在我的环境中打印 -636517714。

PS Actually in the reference documentation we have PS实际上在我们有的参考文档中

@Cacheable(value="books", key="T(someType).hash(#isbn)") 
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

I think that this example is WRONG and misleading and should be removed from the documentation, as the keys should be unique.我认为这个例子是错误的和误导性的,应该从文档中删除,因为键应该是唯一的。

PPS also see https://jira.springsource.org/browse/SPR-9036 for some interesting ideas regarding the default key generation. PPS 还请参阅https://jira.springsource.org/browse/SPR-9036以了解有关默认密钥生成的一些有趣想法。

I'd like to add for the sake of correctness and as an entertaining mathematical/computer science fact that unlike built-in hash, using a secure cryptographic hash function like MD5 or SHA256, due to the properties of such function IS absolutely possible for this task, but to compute it every time may be too expensive, checkout for example Dan Boneh cryptography course to learn more.我想补充的正确性着想,作为一个娱乐数学/计算机科学事实,不像内置散列,使用安全的加密散列函数如MD5或SHA256,由于这类函数的性质这个绝对有可能的任务,但每次都计算它可能太昂贵,请查看例如 Dan Boneh 密码学课程以了解更多信息。

After some limited testing with Spring 3.2, it seems one can use a SpEL list: {..., ..., ...} .在使用 Spring 3.2 进行一些有限的测试后,似乎可以使用 SpEL 列表: {..., ..., ...} This can also include null values.这也可以包括null值。 Spring passes the list as the key to the actual cache implementation. Spring 将列表作为键传递给实际的缓存实现。 When using Ehcache, such will at some point invoke List#hashCode() , which takes all its items into account.当使用 Ehcache 时,它​​会在某个时候调用List#hashCode() ,它会考虑它的所有项目。 (I am not sure if Ehcache only relies on the hash code.) (我不确定 Ehcache 是否依赖于哈希码。)

I use this for a shared cache, in which I include the method name in the key as well, which the Spring default key generator does not include .我将它用于共享缓存,其中我也在密钥中包含方法名称,Spring 默认密钥生成器不包含. This way I can easily wipe the (single) cache, without (too much...) risking matching keys for different methods.这样我就可以轻松擦除(单个)缓存,而不会(太多......)冒着匹配不同方法的密钥的风险。 Like:像:

@Cacheable(value="bookCache", 
  key="{ #root.methodName, #isbn?.id, #checkWarehouse }")
public Book findBook(ISBN isbn, boolean checkWarehouse) 
...

@Cacheable(value="bookCache", 
  key="{ #root.methodName, #asin, #checkWarehouse }")
public Book findBookByAmazonId(String asin, boolean checkWarehouse)
...

Of course, if many methods need this and you're always using all parameters for your key, then one can also define a custom key generator that includes the class and method name:当然,如果很多方法都需要这个,并且你总是为你的密钥使用所有参数,那么你还可以定义一个包含类和方法名称的自定义密钥生成器:

<cache:annotation-driven mode="..." key-generator="cacheKeyGenerator" />
<bean id="cacheKeyGenerator" class="net.example.cache.CacheKeyGenerator" />

...with: ...和:

public class CacheKeyGenerator 
  implements org.springframework.cache.interceptor.KeyGenerator {

    @Override
    public Object generate(final Object target, final Method method, 
      final Object... params) {

        final List<Object> key = new ArrayList<>();
        key.add(method.getDeclaringClass().getName());
        key.add(method.getName());

        for (final Object o : params) {
            key.add(o);
        }
        return key;
    }
}

您可以使用 Spring-EL 表达式,例如在 JDK 1.7 上:

@Cacheable(value="bookCache", key="T(java.util.Objects).hash(#p0,#p1, #p2)")

您可以使用 Spring SimpleKey 类

@Cacheable(value = "bookCache", key = "new org.springframework.cache.interceptor.SimpleKey(#isbn, #checkWarehouse)")

这将工作

@Cacheable(value="bookCache", key="#checkwarehouse.toString().append(#isbn.toString())")

用这个

@Cacheable(value="bookCache", key="#isbn + '_' + #checkWarehouse + '_' + #includeUsed")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM