Hoe vertel ik Spring cache om de null-waarde niet in de cache te plaatsen in @Cacheable annotatie

Is er een manier om aan te geven dat als de methode een null-waarde retourneert, het resultaat dan niet in de @Cacheable-annotatie wordt opgeslagen voor een methode als deze?

@Cacheable(value="defaultCache", key="#pk")
public Person findPerson(int pk) {
   return getSession.getPerson(pk);
}

Bijwerken:
hier is het JIRA-probleem dat afgelopen november is ingediend met betrekking tot het cachen van de null-waarde, die nog niet is opgelost:
[#SPR-8871] @Cachable-voorwaarde moet het mogelijk maken om naar de retourwaarde te verwijzen – Spring Projects Issue Tracker


Antwoord 1, autoriteit 100%

Hoera, vanaf Spring 3.2 staat het framework dit toe met Spring SPEL en unless. Opmerking uit het java-document rond Cacheable:

http: //static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/cache/annotation/Cacheable.html

openbare abstracte tekenreeks tenzij

Spring Expression Language (SpEL)-kenmerk dat wordt gebruikt om methodecaching te weigeren.

In tegenstelling tot condition(), wordt deze expressie geëvalueerd nadat de methode is aangeroepen en kan daarom verwijzen naar het resultaat. De standaardwaarde is “”, wat betekent dat caching nooit wordt verboden.

Het belangrijke aspect is dat unlesswordt geëvalueerd nadat de methode is aangeroepen. Dit is volkomen logisch omdat de methode nooit wordt uitgevoerd als de sleutel zich al in de cache bevindt.

Dus in het bovenstaande voorbeeld zou je gewoon als volgt annoteren (#result is beschikbaar om de geretourneerde waarde van een methode te testen):

@Cacheable(value="defaultCache", key="#pk", unless="#result == null")
public Person findPerson(int pk) {
   return getSession.getPerson(pk);
}

Ik kan me voorstellen dat deze toestand voortkomt uit het gebruik van pluggable cache-implementaties zoals Ehcache die het cachen van nulls mogelijk maakt. Afhankelijk van uw gebruiksscenario kan dit al dan niet wenselijk zijn.


Antwoord 2, autoriteit 4%

updatedit antwoord is nu verouderd, zie voor lente 3.2 en later Tech Trip’s antwoord, OP: markeer het gerust als geaccepteerd.

Ik denk niet dat het mogelijk is (ook al is er voorwaardelijke Cache-uitzetting in Spring die kan worden uitgevoerd na het aanroepen van de methode met @CacheEvictparameter beforeInvocationingesteld op false , wat de standaardwaarde is) als de klasse CacheAspectSupportwordt onderzocht, blijkt dat de geretourneerde waarde nergens is opgeslagen vóór de aanroep 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();
}

Antwoord 3, autoriteit 3%

Als lente-annotatie

@Cacheable(value="defaultCache", key="#pk",unless="#result!=null")

werkt niet, je kunt het proberen:

@CachePut(value="defaultCache", key="#pk",unless="#result==null")

Het werkt voor mij.

Other episodes