@Cacheable多个方法参数的键
从弹簧文档:
@Cacheable(value="bookCache", key="isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
如何指定使用 和 作为键?@Cachable
isbn
checkWarehouse
从弹簧文档:
@Cacheable(value="bookCache", key="isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
如何指定使用 和 作为键?@Cachable
isbn
checkWarehouse
更新:当前 Spring 缓存实现使用所有方法参数作为缓存键(如果未另行指定)。如果要使用选定的键,请参阅Arjan的答案,该答案使用SpEL列表,这是创建唯一键的最简单方法。{#isbn, #includeUsed}
来自春季文档
默认密钥生成策略随着 Spring 4.0 的发布而改变。Spring的早期版本使用了一种密钥生成策略,对于多个密钥参数,只考虑参数的hashCode()而不是equals();这可能会导致意外的密钥冲突(有关背景信息,请参阅 SPR-10237)。新的“SimpleKeyGenerator”在此类场景中使用复合密钥。
春季前 4.0
我建议你将 Spel 表达式中的参数值与类似的东西连接起来,我相信这应该像 org.springframework.cache.interceptor.ExpressionEvaluator 返回 Object 一样工作,Object 稍后用作键,这样你就不必在 SPEL 表达式中提供一个。key="#checkWarehouse.toString() + #isbn.toString()")
int
至于具有高冲突概率的哈希代码 - 您不能将其用作键。
这个线程中的某人建议使用,但它不起作用,这种方法很容易被破坏,例如我使用了SPR-9377中的数据:T(java.util.Objects).hash(#p0,#p1, #p2)
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。
附言:实际上在参考文档中,我们有
@Cacheable(value="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
我认为这个例子是错误的和误导性的,应该从文档中删除,因为键应该是唯一的。
P.P.S. 还请参阅 https://jira.springsource.org/browse/SPR-9036,了解有关默认密钥生成的一些有趣想法。
为了正确起见,我想补充一下,作为一个有趣的数学/计算机科学事实,与内置哈希不同,使用像MD5或SHA256这样的安全加密哈希函数,由于这种函数的属性对于此任务是绝对可能的,但是每次计算它可能太昂贵,例如结帐Dan Boneh密码学课程以了解更多信息。
在对Spring 3.2进行了一些有限的测试之后,似乎可以使用SpEL列表:。这还可以包括值。Spring将列表作为实际缓存实现的关键传递。当使用Ehcache时,它会在某个时候调用List#hashCode(),它会考虑其所有项目。(我不确定Ehcache是否只依赖于哈希代码。{..., ..., ...}
null
我将其用于共享缓存,其中我还在密钥中包含方法名称,而Spring默认密钥生成器不包括该方法名称。通过这种方式,我可以轻松擦除(单个)缓存,而不会(太多...)冒着匹配不同方法的密钥的风险。喜欢:
@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;
}
}