我是缓存和Spring的新手,我无法解决以下来自Spring Docs的示例中cacheNames和Key之间的区别:
@Cacheable(cacheNames="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
据我所知,缓存只是存储在内存中的键值对。因此,在上面的第一次调用示例中,返回的Book值将使用isbn参数的值作为键存储在缓存中。在后续调用中,isbn值与首次请求的值相同,将返回存储在缓存中的Book。可以使用Key找到此Book in cache。那么什么是cacheNames?
我说高速缓存是否存储为如下关键值:
isbn111111 ---> Book,
isbn122222 ---> Book2,
isbn123333 ---> Book3
提前致谢。
答案 0 :(得分:0)
cacheNames是存储数据的缓存本身的名称。您可以拥有多个缓存,例如对于不同的实体类型不同的缓存,或者取决于复制需求等。
答案 1 :(得分:0)
cacheNames的一个重要意义是可以帮助在未将显式键传递给方法时使用@Cacheable的默认键生成。对于使用Spring Cache时未在类级别或方法级别提供cacheNames的人来说,从Spring文档中还不清楚什么是严重错误或不正确的。
答案 2 :(得分:0)
CacheName 更像是一组缓存键。当你打开这个类
org.springframework.cache.interceptor.AbstractCacheResolver
你会发现这个方法可以通过cache
cacheName
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
Collection<String> cacheNames = getCacheNames(context);
if (cacheNames == null) {
return Collections.emptyList();
}
Collection<Cache> result = new ArrayList<>(cacheNames.size());
for (String cacheName : cacheNames) {
Cache cache = getCacheManager().getCache(cacheName);
if (cache == null) {
throw new IllegalArgumentException("Cannot find cache named '" +
cacheName + "' for " + context.getOperation());
}
result.add(cache);
}
return result;
}
所以稍后在 org.springframework.cache.interceptor.CacheAspectSupport
spring 将通过缓存键从 cache
对象获取值
private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
// Special handling of synchronized invocation
if (contexts.isSynchronized()) {
CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();
if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
Cache cache = context.getCaches().iterator().next();
try {
return wrapCacheValue(method, cache.get(key, () -> unwrapReturnValue(invokeOperation(invoker))));
}
catch (Cache.ValueRetrievalException ex) {
// The invoker wraps any Throwable in a ThrowableWrapper instance so we
// can just make sure that one bubbles up the stack.
throw (CacheOperationInvoker.ThrowableWrapper) ex.getCause();
}
}
//...other logic