spring cache 4: CacheAspectSupport
CacheAspectSupport 是 spring 执行 cache 相关操作的核心类
它有5个内部类
- CacheOperationContexts
CacheOperation上下文信息集合,如果把@Cacheable, @CachePut, @CacheEvict通过@Caching的一种特殊形式
那么 CacheOperationContexts 就是可以认为对应一个 @Caching 操作 - CacheOperationMetadata
CacheOperation "静态"元数据,包含CacheOperation, Class, Method, KeyGenerator, CacheResolver - CacheOperationContext
CacheOperation上下文信息,对应一个具体的@Cacheable, @CachePut, @CacheEvict操作
它包含动态的信息,如方法的参数 args,和真正执行方法的对象 target,当然target一般是单例模式 - CachePutRequest
写缓存的请求
一个@Cacheable可能要执行写缓存(缓存不命中时,将执行方法,并将执行结果写到cache中)
一个@CachePut肯定要执行写缓存(不管是否命中,都将执行方法,并将执行结果写到cache中) - CacheOperationCacheKey
一个Class+Mehod+具体的CacheOperation作为一个key,将静态元数据CacheOperationMetadata缓存在 CacheAspectSupport.metadataCache 这个map中
CacheOperationMetadata
"静态"元数据,包含CacheOperation, Class, Method, KeyGenerator, CacheResolver
- CacheOperation 前面讲过了,主要有 CacheableOperation,CachePutOperation,CacheEvictOperation,主要信息就是对应的3个注解中的字段的信息,字符串格式保存
- Class 是执行对象的Class
- Method 是对应的执行方法
- KeyGenerator 用来生成 cache.get 或者 cache.evict 或者 cache.put 中的key
- CacheResolver 用执行的上下文信息(其实就是cacheNames和cacheManager)来获取 Cache 集合对象(cacheManager.getCache(cacheName))
这些信息,如果加上真正执行对象的实例(target)和方法的参数(args)就可以执行缓存的操作了(CacheOperationContext)
protected static class CacheOperationMetadata {
/**
* cache 操作信息
*/
private final CacheOperation operation;
/**
* 执行的方法
*/
private final Method method;
/**
* 执行方法的Class
*/
private final Class<?> targetClass;
/**
* KeyGenerator
* 创建CacheOperationMetadata的地方会根据 CacheOperation 的字符串 keyGenerator 来获取实际的 KeyGenerator 对象
*/
private final KeyGenerator keyGenerator;
/**
* CacheResolver 用来管理 Cache
* 创建CacheOperationMetadata的地方会根据 CacheOperation 的字符串 cacheManager 和 cacheResolver 获取 CacheResolver 对象
*/
private final CacheResolver cacheResolver;
/**
* 需要传入所有私有字段的具体信息
*/
public CacheOperationMetadata(CacheOperation operation, Method method, Class<?> targetClass,
KeyGenerator keyGenerator, CacheResolver cacheResolver) {
this.operation = operation;
this.method = method;
this.targetClass = targetClass;
this.keyGenerator = keyGenerator;
this.cacheResolver = cacheResolver;
}
}
CacheOperationContext
一个具体执行缓存操作的上下文,它主要有3部分组成:
- “静态”元数据 CacheOperationMetadata
- 真正执行对象的实例(target)
- 方法的参数(args)
虽然一个 CacheOperationContext 还有其它信息,但都可以根据 CacheOperationMetadata 获取
protected class CacheOperationContext implements CacheOperationInvocationContext<CacheOperation> {
/**
* cache 操作的元数据
*/
private final CacheOperationMetadata metadata;
/**
* 执行方法的参数
*/
private final Object[] args;
/**
* 执行方法的实例
*/
private final Object target;
/**
* 通过metadata中的CacheOperation.cacheNames和CacheResolver可以获取 Cache集合
*/
private final Collection<? extends Cache> caches;
/**
* 就是 CacheOperation.cacheNames 的一个复制
*/
private final Collection<String> cacheNames;
/**
* Class + Method 作为key,因为 CacheOperationSource(AbstractFallbackCacheOperationSource)中的缓存map是全局的
*/
private final AnnotatedElementKey methodCacheKey;
}
CacheOperationMetadata这个类如果把 private final Class<?> targetClass; 而不是 private Object target; 而 CacheOperationContext 中有private Object target; 和 private final Object[] args; 字段,可能考虑到执行的Class的实例不一定是单例模式,而args是动态产生的
CacheAspectSupport.CacheOperationContext 从名称上看,是CacheOperation操作的上下文,所以每次操作都会new一个新的CacheAspectSupport.CacheOperationContext;所有数据中,只有args字段是动态产生的,target对象如果是单例模式的话,可以认为也是唯一的,其它都是spring启动过程就已经定义好了
所以相对静态的数据存在CacheOperationMetadata中,并且对CacheOperationMetadata缓存在CacheAspectSupport的私有字段metadataCache中
CacheAspectSupport.CacheOperationContext 定义了一些重要方法:
protected boolean isConditionPassing(Object result)
如果condition为空,或者用el表达式判断condition为true时,返回true,表示接下来可能会执行cache相关的操作
condition字段 @Cacheable, @CachePut,@CacheEvict 3种操作都有
protected boolean canPutToCache(Object value)
如果unless为空,或者用el表达式判断unless为true时,返回true,表示接下来需要执行cache相关操作
unless字段只有@Cacheable 和 @CachePut操作才有,所以方法命名叫做canPutToCache
protected Object generateKey(Object result)
通过el表达式计算结果
CacheAspectSupport 的重要方法
getCacheOperationMetadata
protected CacheOperationMetadata getCacheOperationMetadata(
CacheOperation operation, Method method, Class<?> targetClass) {
// 生成从map中获取的key,key由Class+Method+CateogryOperation组成
CacheOperationCacheKey cacheKey = new CacheOperationCacheKey(operation, method, targetClass);
CacheOperationMetadata metadata = this.metadataCache.get(cacheKey);
if (metadata == null) {
// 如果metadataCache缓存中没有,计算出 CacheOperationMetadata 并将结果放入到metadataCache缓存中
KeyGenerator operationKeyGenerator;
if (StringUtils.hasText(operation.getKeyGenerator())) {
// 如果@Cacheable,@CachePut,@CacheEvict这些注解中配置了 keyGenerator 的话,获取 KeyGenerator 对象
operationKeyGenerator = getBean(operation.getKeyGenerator(), KeyGenerator.class);
}
else {
// 如果@Cacheable,@CachePut,@CacheEvict这些注解中没有配置 keyGenerator 的话,获取默认的 KeyGenerator 对象
operationKeyGenerator = getKeyGenerator();
}
CacheResolver operationCacheResolver;
if (StringUtils.hasText(operation.getCacheResolver())) {
// 如果@Cacheable,@CachePut,@CacheEvict这些注解中配置了 cacheResolver 的话,获取 CacheResolver 对象
operationCacheResolver = getBean(operation.getCacheResolver(), CacheResolver.class);
}
else if (StringUtils.hasText(operation.getCacheManager())) {
// 如果@Cacheable,@CachePut,@CacheEvict这些注解中配置了 cacheManager 的话,获取 CacheManager 来构造 SimpleCacheResolver 对象
CacheManager cacheManager = getBean(operation.getCacheManager(), CacheManager.class);
operationCacheResolver = new SimpleCacheResolver(cacheManager);
}
else {
// 如果@Cacheable,@CachePut,@CacheEvict这些注解中没有配置了 cacheResolver 和 cacheManager 的话
// 获取默认的 CacheResolver
// afterSingletonsInstantiated() 的时候判断,如果默认的 cacheResolver==null 的话,会new一个对象
operationCacheResolver = getCacheResolver();
}
// 计算出 CacheOperationMetadata 并将结果放入到metadataCache缓存中
metadata = new CacheOperationMetadata(operation, method, targetClass,
operationKeyGenerator, operationCacheResolver);
this.metadataCache.put(cacheKey, metadata);
}
return metadata;
}
execute
protected Object execute(CacheOperationInvoker 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) {
// 已经初始化完成
Class<?> targetClass = getTargetClass(target);
// 根据Class+Method获取 Collection<CacheOperation>
Collection<CacheOperation> operations = getCacheOperationSource().getCacheOperations(method, targetClass);
if (!CollectionUtils.isEmpty(operations)) {
return execute(invoker, new CacheOperationContexts(operations, method, args, target, targetClass));
}
}
// 如果未初始化好,不走缓存相关的逻辑
return invoker.invoke();
}
// 这个代码,可以结合 @Caching 注解看,一个method上可能 @Cacheable,@CachePut,@CacheEvict 的各种组合
// 单个 @Cacheable,@CachePut, @CacheEvict只是其中一种特殊情况
private Object execute(CacheOperationInvoker invoker, CacheOperationContexts contexts) {
// 如果有 @CacheEvict 注解,并且 beforeInvocation==true 执行 cache.evict(key);
processCacheEvicts(contexts.get(CacheEvictOperation.class), true, ExpressionEvaluator.NO_RESULT);
// 不管是否有 @Cacheable 注解,都查一下缓存
// 如果 cacheName 所在的 cache 缓存命中,返回 Cache.ValueWrapper 对象(这个对象非null,但是getValue可能为null),否则返回 null
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
// 如果缓存不命中,并且有 @Cacheable ,后续需要放在缓存中,收集这些请求,收集中需要注意 condition 的判断
// 【注意】:这里没有收集 @CachePut,因为 @CachePut 一定会执行方法,并将结果放入到 cache,后面的代码会有这个逻辑
List<CachePutRequest> cachePutRequests = new LinkedList<CachePutRequest>();
if (cacheHit == null) {
// 虽然缓存没命中,但收集到的 CacheableOperation 操作可能没有
// 因为前面代码时:"不管是否有 @Cacheable 注解,都查一下缓存"
collectPutRequests(contexts.get(CacheableOperation.class), ExpressionEvaluator.NO_RESULT, cachePutRequests);
}
Cache.ValueWrapper result = null;
// 这段代码非常巧妙的为后续用到 resutlt==null 这个判断条件
// 将这段代码等价于:
// if (hasCachePut(contexts) || !cachePutRequest.isEmpty()) {
// result == null;
// } else {
// result = cacheHit;
// }
//
if (cachePutRequests.isEmpty() && !hasCachePut(contexts)) {
// 没有满足 condition 的 @Cacheable 操作,或者 当前没有满足condition的 @CachePut 操作
// 没有满足 condition 的XXX操作的含义是:没有XXX注解,或者有XXX注解,但是condition不满足
result = cacheHit;
}
// Invoke the method if don't have a cache hit
if (result == null) {
// 执行真正的方法体,并把返回结果包装一下
result = new SimpleValueWrapper(invokeOperation(invoker));
}
// 收集 @CachePut 的写缓存请求
// 【注意】:这里会处理 unless 逻辑,只有满足unless逻辑的,才可以写到缓存中
collectPutRequests(contexts.get(CachePutOperation.class), result.get(), cachePutRequests);
// 涉及到写缓存的请求,执行 cache.put
for (CachePutRequest cachePutRequest : cachePutRequests) {
cachePutRequest.apply(result.get());
}
// 处理 @CacheEvict 请求,处理 cache.evict 或者 cache.clear (allEntries=true)
processCacheEvicts(contexts.get(CacheEvictOperation.class), false, result.get());
// 返回结果
return result.get();
}