Как сообщить Spring кешу не кэшировать нулевое значение в аннотации @Cacheable
Есть ли способ указать, что если метод возвращает значение null, то не кэшируйте результат в аннотации @Cacheable для такого метода?
@Cacheable(value="defaultCache", key="#pk")
public Person findPerson(int pk) {
return getSession.getPerson(pk);
}
Обновление: вот вопрос JIRA, представленный относительно кэширования нулевого значения в ноябре прошлого года, который еще не решен: [# SPR-8871] Условие @Cachable должно разрешать ссылку на возвращаемое значение - Spring Projects Issue Tracker
Ответы
Ответ 1
Hooray, а весны 3.2 рамки позволяет для этого с помощью Spring SPEL и unless
. Примечание из java-документа, окружающего Cacheable:
http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/cache/annotation/Cacheable.html
публичная аннотация String if
Атрибут Spring Expression Language (Spel), используемый для кэширования методов вето.
В отличие от условия() это выражение оценивается после вызова метода и поэтому может ссылаться на результат. Значение по умолчанию - "", что означает, что кеширование никогда не накладывается вето.
Важным аспектом является то, что unless
оценка unless
будет оценена после вызова метода. Это имеет смысл, потому что метод никогда не будет выполнен, если ключ уже находится в кеше.
Поэтому в приведенном выше примере вы просто аннотируете следующее (#result доступен для проверки возвращаемого значения метода):
@Cacheable(value="defaultCache", key="#pk", unless="#result == null")
public Person findPerson(int pk) {
return getSession.getPerson(pk);
}
Я бы предположил, что это условие возникает из-за использования подключаемых кэш-реализаций, таких как Ehcache, который позволяет кэшировать нули. В зависимости от вашего сценария использования это может быть или не быть желательным.
Ответ 2
обновить этот ответ устарел сейчас, для Spring 3.2 и более поздних см. ответ Tech Trip, OP: не стесняйтесь отмечать его как принятый.
Я не думаю, что это возможно (даже если условное выселение Cache в Spring, которая может быть выполнена после вызова метода с @CacheEvict
параметра beforeInvocation значения ЛЖИ, что значение по умолчанию) изучение 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();
}
Ответ 3
Если весенняя аннотация
@Cacheable(value="defaultCache", key="#pk",unless="#result!=null")
не работает, вы можете попробовать:
@CachePut(value="defaultCache", key="#pk",unless="#result==null")
Меня устраивает.