使用spring cache read only,如何设置spring cache cache redis只读

时间:2015-12-19 11:20:46

标签: spring-cache

当我使用带有 redis 的弹簧缓存时,我在两个应用程序中使用它,一个读写,另一个只读,我该怎么配置?

我尝试这样做,但它不起作用!

@Cacheable(value = "books", key = "#isbn", condition = "false")

有人可以帮忙吗?

3 个答案:

答案 0 :(得分:2)

您误解了del data_Crime[:]注释" @Cacheable"的目的?属性。根据{{​​3}} ...

  

如果为true,则缓存该方法 - 如果不是,则其行为就像方法一样   没有缓存,无论什么值,都会在每个时间执行   在缓存中或使用了什么参数。

condition属性仅确定在执行(可能是昂贵的)方法之前是否首先查询缓存(例如Redis)。如果condition评估为 false ,则始终会执行该方法并随后缓存结果。

在只读应用程序中,我假设您希望首先查询缓存,如果该值不在缓存中,则执行该方法,但是,请勿缓存结果。这是对的吗?

如果是这样,那么您只需要指定condition属性而不是unless属性,就像这样......

condition

但是,如果您想完全避免只读(版本)应用程序中的可缓存方法调用,并且只是查询缓存而不管缓存中是否存在某个值,那么您的问题是相当的有点复杂/困难。

Spring的高速缓存抽象操作的前提是,如果一个值不在高速缓存中,那么它将返回null以指示高速缓存未命中,然后是后续的方法调用。只有当缓存返回指定键的值时,才会避免方法调用。

没有自定义扩展(可能使用(附加)AOP拦截器),无法避免OOTB行为。

除非您的用例需要,否则我不会详细说明这种后期技术。

希望这有帮助。

答案 1 :(得分:0)

@Tonney Bing

首先,我为你以前的回答误导你道歉......

  

如果条件评估为 false ,则该方法将始终为   执行,结果随后缓存

最后一部分不是真的。实际上,condition属性确实会阻止缓存@Cacheable方法结果。但是,conditionunless属性都不会阻止调用@Cacheable服务方法。

另外,我上面的代码示例不正确。 unless属性需要设置为 true ,以防止缓存@Cacheable方法结果。

在Spring参考指南中重新阅读this section之后,我意识到自己的错误并编写了example test class来验证Spring的“条件”缓存行为。

因此...

关于您的业务用例,我根据您的原始问题理解它的方式,随后,您对我之前的答案的回复,您有一个@Cacheable服务方法需要抑制调用只读应用程序,无论该值是否在缓存中!换句话说,应始终从缓存中检索该值,@Cacheable服务方法应以只读模式调用 NOT

现在要避免使用 Spring 基础架构组件引用来污染您的应用程序代码,特别是使用 Spring CacheManager,这是一个很好的例子。跨界关注“(因为可能存在多个基于变异的应用服务操作),因此可以使用AOP进行适当处理。

我编写了这样一个满足您要求的示例here

这是一个独立的测试类。该测试类的主要特征包括......

  1. 使用外部配置(通过app.mode.read-only系统属性)来确定应用程序是否处于只读模式。

  2. 使用AOP和自定义Aspect来控制是否允许后续调用Joint Point(即@Cacheable服务方法)(不,在只读上下文中)。此外,我还适当地设置了建议(即基于@Cacheable的建议以及handleReadOnlyMode方面的UseCacheExclusivelyInReadOnlyModeAspect建议)应根据优先级触发的顺序。

  3. 记下服务方法的@Cacheable注释......

    @Cacheable(value = "Factorials", unless = "T(java.lang.System).getProperty('app.mode.read-only', 'false')")
    public Long factorial(long number) { .. }
    
  4. 您可以在测试类中看到System.err输出语句的预期行为。

    希望这有帮助!

答案 2 :(得分:0)

@John Blum 谢谢!新年快乐。 你的回答激发了我,我已经阅读了弹簧缓存源代码的一部分。 CacheInterceptor类。 CacheAspectSupport类。

private Object execute(CacheOperationInvoker invoker, CacheOperationContexts contexts) {
        // Process any early evictions
        processCacheEvicts(contexts.get(CacheEvictOperation.class), true, ExpressionEvaluator.NO_RESULT);

        // Check if we have a cached item matching the conditions
        Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));

        // Collect puts from any @Cacheable miss, if no cached item is found
        List<CachePutRequest> cachePutRequests = new LinkedList<CachePutRequest>();
        if (cacheHit == null) {
            collectPutRequests(contexts.get(CacheableOperation.class), ExpressionEvaluator.NO_RESULT, cachePutRequests);
        }

        Cache.ValueWrapper result = null;

        // If there are no put requests, just use the cache hit
        if (cachePutRequests.isEmpty() && !hasCachePut(contexts)) {
            result = cacheHit;
        }

        // Invoke the method if don't have a cache hit
        if (result == null) {
            result = new SimpleValueWrapper(invokeOperation(invoker));
        }

        // Collect any explicit @CachePuts
        collectPutRequests(contexts.get(CachePutOperation.class), result.get(), cachePutRequests);

        // Process any collected put requests, either from @CachePut or a @Cacheable miss
        for (CachePutRequest cachePutRequest : cachePutRequests) {
            cachePutRequest.apply(result.get());
        }

        // Process any late evictions
        processCacheEvicts(contexts.get(CacheEvictOperation.class), false, result.get());

        return result.get();
    }

我认为应该阻止cachePutRequest执行。如果没有命中缓存,则调用@Cacheable的方法体并且不缓存结果。 use除非会阻止方法调用。这是对的吗?