简体   繁体   English

如何告诉Spring缓存不要在@Cacheable注释中缓存空值

[英]How do I tell Spring cache not to cache null value in @Cacheable annotation

Is there a way to specify that if the method returns null value, then don't cache the result in @Cacheable annotation for a method like this? 有没有办法指定如果方法返回null值,那么不要将结果缓存在这样的方法的@Cacheable注释中?

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

Update: here is the JIRA issue submitted regarding caching null value last November, which hasn't resolved yet: [#SPR-8871] @Cachable condition should allow referencing return value - Spring Projects Issue Tracker 更新:以下是去年11月提交的关于缓存空值的JIRA问题,尚未解决: [#SPR-8871] @Cachable条件应允许引用返回值 - Spring Projects问题跟踪器

Hooray, as of Spring 3.2 the framework allows for this using Spring SPEL and unless . Hooray,从Spring 3.2开始,框架允许使用Spring SPEL, unless Note from the java doc surrounding Cacheable: 关于Cacheable的java doc中的注意事项:

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

public abstract String unless public abstract String除非

Spring Expression Language (SpEL) attribute used to veto method caching. Spring Expression Language(SpEL)属性用于否决方法缓存。

Unlike condition(), this expression is evaluated after the method has been called and can therefore refer to the result. 与condition()不同,此表达式在调用方法后进行计算,因此可以引用结果。 Default is "", meaning that caching is never vetoed. 默认为“”,表示缓存永远不会被否决。

The important aspect is that unless is evaluated after the method has been called. 重要的方面是unless在调用方法之后进行评估。 This makes perfect sense because the method will never get executed if the key is already in the cache. 这非常有意义,因为如果密钥已经在缓存中,则永远不会执行该方法。

So in the above example you would simply annotate as follows (#result is available to test the return value of a method): 因此,在上面的示例中,您只需注释如下(#result可用于测试方法的返回值):

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

I would imagine this condition arises from the use of pluggable cache implementations such as Ehcache which allows caching of nulls. 我想这种情况源于使用可插入缓存实现,如Ehcache,它允许缓存空值。 Depending on your use case scenario this may or may not be desirable. 根据您的使用案例情况,这可能是也可能不是。

update this answer is outdated now, for Spring 3.2 and later see Tech Trip's answer , OP: feel free to mark it as accepted. 更新此答案现已过时,对于Spring 3.2及更高版本,请参阅Tech Trip的答案 ,OP:随时将其标记为已接受。

I don't think that it's possible(even though there's conditional Cache eviction in Spring that can be executed after the method invocation with @CacheEvict parameter beforeInvocation set to false, which is default value) examining the CacheAspectSupport class shows that the returned value is not stored anywhere before the inspectAfterCacheEvicts(ops.get(EVICT)); 我不认为这是可能的(即使Spring中的条件Cache驱逐可以在使用@CacheEvict参数beforeInvocation设置为false的方法调用之后执行,这是默认值)检查CacheAspectSupport类显示返回的值不是存储在inspectAfterCacheEvicts(ops.get(EVICT));之前的任何地方inspectAfterCacheEvicts(ops.get(EVICT)); call. 呼叫。

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();
}

If Spring annotation 如果是Spring注释

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

does not work ,you can try: 不起作用,你可以尝试:

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

It works for me. 这个对我有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM