当我使用带有 redis 的弹簧缓存时,我在两个应用程序中使用它,一个读写,另一个只读,我该怎么配置?
我尝试这样做,但它不起作用!
@Cacheable(value = "books", key = "#isbn", condition = "false")
有人可以帮忙吗?
答案 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
方法结果。但是,condition
和unless
属性都不会阻止调用@Cacheable
服务方法。
另外,我上面的代码示例不正确。 unless
属性需要设置为 true ,以防止缓存@Cacheable
方法结果。
在Spring参考指南中重新阅读this section之后,我意识到自己的错误并编写了example test class来验证Spring的“条件”缓存行为。
因此...
关于您的业务用例,我根据您的原始问题理解它的方式,随后,您对我之前的答案的回复,您有一个@Cacheable
服务方法需要抑制调用只读应用程序,无论该值是否在缓存中!换句话说,应始终从缓存中检索该值,@Cacheable
服务方法应以只读模式调用 NOT 。
现在要避免使用 Spring 基础架构组件引用来污染您的应用程序代码,特别是使用 Spring CacheManager
,这是一个很好的例子。跨界关注“(因为可能存在多个基于变异的应用服务操作),因此可以使用AOP进行适当处理。
我编写了这样一个满足您要求的示例here。
这是一个独立的测试类。该测试类的主要特征包括......
使用外部配置(通过app.mode.read-only
系统属性)来确定应用程序是否处于只读模式。
使用AOP和自定义Aspect来控制是否允许后续调用Joint Point(即@Cacheable服务方法)(不,在只读上下文中)。此外,我还适当地设置了建议(即基于@Cacheable
的建议以及handleReadOnlyMode
方面的UseCacheExclusivelyInReadOnlyModeAspect
建议)应根据优先级触发的顺序。
记下服务方法的@Cacheable
注释......
@Cacheable(value = "Factorials", unless = "T(java.lang.System).getProperty('app.mode.read-only', 'false')")
public Long factorial(long number) { .. }
您可以在测试类中看到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除非会阻止方法调用。这是对的吗?