80

メソッドがnull値を返す場合、このようなメソッドの@Cacheableアノテーションに結果をキャッシュしないように指定する方法はありますか?

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

更新:昨年11月にnull値のキャッシュに関して提出されたJIRAの問題は、まだ解決されていません: [#SPR-8871] @Cachable条件により、戻り値の参照が可能になるはずです-Spring Projects Issue Tracker

4

3 に答える 3

150

Hooray、Spring 3.2の時点で、フレームワークはSpringSPELとを使用してこれを可能にしunlessます。Cacheableを取り巻くJavadocからの注意:

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

パブリック抽象文字列

メソッドのキャッシュを拒否するために使用されるSpringExpressionLanguage(SpEL)属性。

condition()とは異なり、この式はメソッドが呼び出された後に評価されるため、結果を参照できます。デフォルトは「」です。これは、キャッシュが拒否されないことを意味します。

重要な側面はunless、メソッドが呼び出された後に評価されることです。キーがすでにキャッシュにある場合、メソッドは実行されないため、これは完全に理にかなっています。

したがって、上記の例では、次のように単純にアノテーションを付けます(#resultは、メソッドの戻り値をテストするために使用できます)。

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

この状態は、nullのキャッシュを可能にするEhcacheなどのプラグ可能なキャッシュ実装の使用から発生すると思います。ユースケースのシナリオに応じて、これは望ましい場合と望ましくない場合があります。

于 2013-04-02T22:12:42.027 に答える
6

この回答を更新すると、現在は古くなっています。Spring3.2以降では、Tech Tripの回答を参照してください。OP:承認済みとしてマークしてください。

@CacheEvict(デフォルト値であるfalseに設定されたパラメーターbeforeInvocationでメソッド呼び出しの後に実行できるSpringの条件付きキャッシュエビクションがあるとしても)クラスを調べる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();
}
于 2012-08-24T17:52:04.540 に答える
4

Springアノテーションの場合

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

動作しません、あなたは試すことができます:

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

わたしにはできる。

于 2017-03-02T02:47:21.850 に答える