有没有办法指定如果方法返回null值,那么不要将结果缓存到这样的方法的@Cacheable注释中?
@Cacheable(value="defaultCache", key="#pk")
public Person findPerson(int pk) {
return getSession.getPerson(pk);
}
更新: 这是去年11月提交的关于缓存空值的JIRA问题,尚未解决: [#SPR-8871] @Cachable condition should allow referencing return value - Spring Projects Issue Tracker
答案 0 :(得分:89)
Hooray,从Spring 3.2开始,框架允许使用Spring SPEL和unless
。请参阅围绕Cacheable的java doc:
public abstract String,除非
用于否决方法缓存的Spring Expression Language(SpEL)属性。
与condition()不同,此表达式在调用方法后进行计算,因此可以引用结果。默认为“”,表示缓存永远不会被否决。
重要的方面是在调用方法后评估unless
。这非常有意义,因为如果密钥已经在缓存中,则永远不会执行该方法。
因此,在上面的示例中,您只需注释如下(#result可用于测试方法的返回值):
@Cacheable(value="defaultCache", key="#pk", unless="#result == null")
public Person findPerson(int pk) {
return getSession.getPerson(pk);
}
我认为这种情况源于使用可插入缓存实现,例如Ehcache,它允许缓存空值。根据您的使用案例情况,这可能是也可能不合适。
答案 1 :(得分:3)
更新此答案现已过时,对于Spring 3.2及更高版本,请参阅Tech Trip的answer,OP:随时将其标记为已接受。
我不认为这是可能的(尽管Spring中的条件Cache驱逐可以在@CacheEvict
参数 beforeInvocation 设置为false的方法调用之后执行,这是默认的值)检查CacheAspectSupport
类显示返回的值未存储在inspectAfterCacheEvicts(ops.get(EVICT));
调用之前的任何位置。
protected Object execute(Invoker invoker, Object target, Method method, Object[] args) {
// check whether aspect is enabled
// to cope with cases where the AJ is pulled in automatically
if (!this.initialized) {
return invoker.invoke();
}
// get backing class
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
if (targetClass == null && target != null) {
targetClass = target.getClass();
}
final Collection<CacheOperation> cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass);
// analyze caching information
if (!CollectionUtils.isEmpty(cacheOp)) {
Map<String, Collection<CacheOperationContext>> ops = createOperationContext(cacheOp, method, args, target, targetClass);
// start with evictions
inspectBeforeCacheEvicts(ops.get(EVICT));
// follow up with cacheable
CacheStatus status = inspectCacheables(ops.get(CACHEABLE));
Object retVal = null;
Map<CacheOperationContext, Object> updates = inspectCacheUpdates(ops.get(UPDATE));
if (status != null) {
if (status.updateRequired) {
updates.putAll(status.cUpdates);
}
// return cached object
else {
return status.retVal;
}
}
retVal = invoker.invoke();
inspectAfterCacheEvicts(ops.get(EVICT));
if (!updates.isEmpty()) {
update(updates, retVal);
}
return retVal;
}
return invoker.invoke();
}
答案 2 :(得分:2)
如果是Spring注释
@Cacheable(value="defaultCache", key="#pk",unless="#result!=null")
不起作用,您可以尝试:
@CachePut(value="defaultCache", key="#pk",unless="#result==null")
它对我有用。