多个方法参数的@Cacheable键

从spring文档 :

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

我怎样才能指定@Cachable使用isbncheckWarehouse作为关键?

更新 :当前的Springcaching实现使用所有的方法参数作为caching键,否则没有指定。 如果你想使用选定的键,请参考Arjan的使用SpEL列表{#isbn, #includeUsed} 的答案 ,这是创build唯一键的最简单的方法。

从Spring文档

默认的密钥生成策略随着Spring 4.0的发布而改变。 Spring的早期版本使用了一个密钥生成策略,对于多个关键参数,只考虑参数的hashCode()而不考虑equals(); 这可能会导致意外的关键冲突(请参见SPR-10237的背景)。 新的“SimpleKeyGenerator”为这种情况使用了一个复合键。

在Spring 4.0之前

我build议你使用类似于key="#checkWarehouse.toString() + #isbn.toString()")来连接Spelexpression式中的参数值,我相信这应该像org.springframework.cache.interceptor.ExpressionEvaluator返回Object,后者用作键,所以不必在SPELexpression式中提供int

至于碰撞概率很高的散列码 – 你不能用它作为关键。

在这个线程中有人build议使用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))); 

两行都在我的环境中打印-636517714。

PS其实在我们的参考文件

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

我认为这个例子是错误的和误导性的,应该从文档中删除,因为这些密钥应该是唯一的。

关于默认密钥生成的一些有趣的想法,PPS也见https://jira.springsource.org/browse/SPR-9036

为了正确性和作为一个有趣的事实,我想添加一个有趣的事实,即使用像SHA256这样的安全密码散列函数 ,由于这个函数的性质可能的,但是每次计算它可能太昂贵了。

在使用Spring 3.2进行一些有限的testing后,似乎可以使用SpEL列表: {..., ..., ...} 。 这也可以包含null值。 Spring将列表作为实际caching实现的关键。 当使用Ehcache时,会在某个时候调用List#hashCode() ,它将所有的项目都考虑在内。 (我不确定Ehcache是​​否依赖哈希码。)

我使用这个共享caching,其中我也包括方法名称 ,以及Spring默认密钥生成器不包括 。 这样,我可以轻松地擦除(单个)caching,而不用(为…)冒着不同方法匹配键的风险。 喜欢:

 @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) ... 

当然,如果有许多方法需要这个,而且你总是使用你的密钥的所有参数,那么你也可以定义一个包含类和方法名的自定义密钥生成器:

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

…有:

 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-ELexpression式,例如在JDK 1.7上:

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

这将工作

@Cacheable(value =“bookCache”,key =“#checkwarehouse.toString()。append(#isbn.toString())”)

用这个

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