多个方法参数的@Cacheable键
从spring文档 :
@Cacheable(value="bookCache", key="isbn") public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
我怎样才能指定@Cachable
使用isbn
和checkWarehouse
作为关键?
更新 :当前的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")