2012-08-24 18 views
35

¿Hay alguna forma de especificar que si el método arroja un valor nulo, no almacene el resultado en la anotación @Cacheable para un método como este?¿Cómo le digo a Spring Cache que no almacene en caché el valor nulo en la anotación @Cacheable

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

Actualización: aquí está el problema JIRA presentado en relación con el almacenamiento en caché valor nulo en noviembre pasado, que no ha resuelto todavía: [#SPR-8871] @Cachable condition should allow referencing return value - Spring Projects Issue Tracker

+0

Hola, creo que debes aceptar la respuesta de Tech Trip porque es más relevante para la versión actual de Spring. –

Respuesta

59

Hooray, como de la primavera 3.2 el marco permite para este utilizando Spring SPEL y unless. Nota del doc java que rodea cacheable:

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

cadena pública abstracta menos

Expresión primavera Idioma atributo (SpEL) utilizado para vetar método de almacenamiento en caché.

A diferencia de la condición(), esta expresión se evalúa después de llamar al método y, por lo tanto, puede hacer referencia al resultado. El valor predeterminado es "", lo que significa que el almacenamiento en caché nunca se veta.

El aspecto importante es que unless se evalúa después de haber llamado al método. Esto tiene mucho sentido porque el método nunca se ejecutará si la clave ya está en la memoria caché.

Así en el ejemplo anterior sólo tendría que anotar la siguiente manera (#result está disponible para probar el valor de retorno de un método):

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

Me imagino que esta condición se deriva del uso de implementaciones de caché enchufables como Ehcache, que permite el almacenamiento en caché de nulos. Dependiendo de su escenario de caso de uso, esto puede o no ser deseable.

+0

Hola, tengo un escenario en el que el servidor de redis caching almacena en caché las excepciones. Tengo que evitar el almacenamiento en caché de excepciones al servidor. ¿Puedo usar el parámetro "a menos" para esto? ¿Es posible mencionar excepciones en menos? Por favor comparte tus sugerencias.Gracias de antemano – nijogeorgep

+0

JSR107 proporciona un mecanismo para invocar siempre el método anotado y aún almacenar en caché el resultado a través de cacheResult # skipGet. De acuerdo con la API en skipGet, si es verdadero, también se salta la verificación previa a la invocación de una excepción lanzada. Sin embargo, si se lanza una excepción durante la invocación, se almacenará en caché siguiendo las reglas estándar de caché de excepciones, por lo que puede no ser suficiente para sus necesidades. Sin embargo, usando JSR 107 puedes excluir explícitamente ciertas excepciones en config y quizás eso te permita seguir. (Consulte nonCachedExceptions) La abstracción de Spring proporciona compatibilidad con las anotaciones JSR107. – TechTrip

2

actualización esta respuesta es obsoleta ahora, para Spring 3.2 y posteriores vea Tech Trip's answer, OP: no dude en marcarlo como aceptado.

No creo que es posible (aunque no es condicional desalojo caché en la primavera que se puede ejecutar después de la invocación del método con @CacheEvict parámetro beforeInvocation establece en false, que es el valor por defecto) el examen de la clase CacheAspectSupport muestra que el valor devuelto no se almacena en ningún lugar antes de la llamada 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(); 
} 
0

Si la anotación de la primavera

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

no funciona, puede intentar:

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

Funciona para mí.

+5

¿quisiste decir 'unless =" # result == null "'? – cahen

+0

_Cache a menos que el resultado! = Null_means _Cache si result == null_. Entonces, la expresión correcta es 'unless =" # result == null "' que significa _Cache a menos que result == null_ lo que significa _Cache si result! = Null_. – mmdemirbas

Cuestiones relacionadas