Existe-t-il un moyen de spécifier que si la méthode renvoie une valeur nulle, ne mettez pas le résultat en cache dans l'annotation @Cacheable pour une méthode comme celle-ci?
@Cacheable(value="defaultCache", key="#pk")
public Person findPerson(int pk) {
return getSession.getPerson(pk);
}
Mise à jour: voici le problème JIRA soumis concernant la mise en cache de la valeur nulle en novembre dernier, qui n'a pas encore été résolu: [# SPR-8871] La condition @Cachable devrait permettre de référencer la valeur de retour - Spring Projects Issue Tracker
Hourra, à partir de Spring 3.2, le framework permet cela en utilisant Spring SPEL et unless
. Note du document Java entourant Cacheable:
chaîne abstraite publique sauf
Attribut Spring Expression Language (SpEL) utilisé pour opposer un veto à la mise en cache des méthodes.
Contrairement à condition (), cette expression est évaluée après l'appel de la méthode et peut donc faire référence au résultat. La valeur par défaut est "", ce qui signifie que la mise en cache n'est jamais refusée.
L'aspect important est que unless
est évalué après l'appel de la méthode. Cela est parfaitement logique car la méthode ne sera jamais exécutée si la clé est déjà dans le cache.
Ainsi, dans l'exemple ci-dessus, vous annoteriez simplement comme suit (#result est disponible pour tester la valeur de retour d'une méthode):
@Cacheable(value="defaultCache", key="#pk", unless="#result == null")
public Person findPerson(int pk) {
return getSession.getPerson(pk);
}
J'imagine que cette condition découle de l'utilisation d'implémentations de cache enfichables telles que Ehcache qui permet la mise en cache des valeurs nulles. Selon votre scénario d'utilisation, cela peut être souhaitable ou non.
mise à jour cette réponse est désormais obsolète, pour Spring 3.2 et versions ultérieures voir Tech Trip answer , OP: n'hésitez pas à la marquer comme accepté.
Je ne pense pas que ce soit possible (même s'il y a une éviction conditionnelle du cache au printemps qui peut être exécutée après l'invocation de la méthode avec le paramètre @CacheEvict
beforeInvocation défini sur false, ce qui est par défaut value) l'examen de la classe CacheAspectSupport
montre que la valeur retournée n'est stockée nulle part avant l'appel de 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();
}
Si annotation de printemps
@Cacheable(value="defaultCache", key="#pk",unless="#result!=null")
ne fonctionne pas, vous pouvez essayer:
@CachePut(value="defaultCache", key="#pk",unless="#result==null")
Ça marche pour moi.