spring cache 4: CacheAspectSupport


CacheAspectSupport 是 spring 执行 cache 相关操作的核心类

它有5个内部类

  1. CacheOperationContexts
    CacheOperation上下文信息集合,如果把@Cacheable, @CachePut, @CacheEvict通过@Caching的一种特殊形式
    那么 CacheOperationContexts 就是可以认为对应一个 @Caching 操作
  2. CacheOperationMetadata
    CacheOperation "静态"元数据,包含CacheOperation, Class, Method, KeyGenerator, CacheResolver
  3. CacheOperationContext
    CacheOperation上下文信息,对应一个具体的@Cacheable, @CachePut, @CacheEvict操作
    它包含动态的信息,如方法的参数 args,和真正执行方法的对象 target,当然target一般是单例模式
  4. CachePutRequest
    写缓存的请求
    一个@Cacheable可能要执行写缓存(缓存不命中时,将执行方法,并将执行结果写到cache中)
    一个@CachePut肯定要执行写缓存(不管是否命中,都将执行方法,并将执行结果写到cache中)
  5. 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部分组成:

  1. “静态”元数据 CacheOperationMetadata
  2. 真正执行对象的实例(target)
  3. 方法的参数(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();
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值