前言CacheInterceptorCacheAspectSupport
1 - 关于缓存操作的属性相关2 - 从 execute 方法入手3 - CacheOperationContexts4 - getOperationContext5 - execute AbstractCacheInvoker总结
前言之前的章节了解到,@EnableCaching 最终会引入组件 BeanFactoryCacheOperationSourceAdvisor,基于 Advisor = Advice + Pointcut,其中 Advice 就是 CacheInterceptor,本章节具体了解 CacheInterceptor 相关类:即 Spring Cache 行为的实现逻辑
CacheInterceptorpublic class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {
@Override
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
// 缓存操作本身的执行,比如:缓存中未查到,或者更新缓存结果等时
CacheOperationInvoker aopAllianceInvoker = () -> {
try {
return invocation.proceed();
}
catch (Throwable ex) {
throw new CacheOperationInvoker.ThrowableWrapper(ex);
}
};
Object target = invocation.getThis();
Assert.state(target != null, "Target must not be null");
try {
return execute(aopAllianceInvoker, target, method, invocation.getArguments());
}
catch (CacheOperationInvoker.ThrowableWrapper th) {
throw th.getOriginal();
}
}
}
首先,CacheInterceptor 是一个 MethodInterceptor,它代表整个切面拦截链的执行,执行逻辑封装在父类方法 CacheAspectSupport#executeCacheOperationInvoker 接口代表被缓存方法的执行,这里内部类的实现即 MethodInvocation#proceed关于 MethodInterceptor MethodInvocation 等更多细节,可以参考下文:
【源码】Spring AOP 2 Advice
【源码】Spring AOP 3 Joinpoint
CacheAspectSupport这是整个 CacheInterceptor 逻辑实现的核心基类,所以内容比较多,以个人角度分几个部分了解:
1 - 关于缓存操作的属性相关private final MapmetadataCache = new ConcurrentHashMap<>(1024); // 负责 SpEL 解析 private final CacheOperationexpressionevaluator evaluator = new CacheOperationexpressionevaluator(); // 用来解析指定方法的 CacheOperation @Nullable private CacheOperationSource cacheOperationSource; // 默认的 KeyGenerator 是 SimpleKeyGenerator private SingletonSupplier keyGenerator = SingletonSupplier.of(SimpleKeyGenerator::new); @Nullable private SingletonSupplier cacheResolver; // 本身是一个 BeanFactoryAware @Nullable private BeanFactory beanFactory; // 属性初始化的标识 private boolean initialized = false; // 这里通常是基于 CacheConfigurer 进行配置 public void configure( @Nullable Supplier errorHandler, @Nullable Supplier keyGenerator, @Nullable Supplier cacheResolver, @Nullable Supplier cacheManager) { // 默认 SimpleCacheErrorHandler this.errorHandler = new SingletonSupplier<>(errorHandler, SimpleCacheErrorHandler::new); // 默认 SimpleKeyGenerator this.keyGenerator = new SingletonSupplier<>(keyGenerator, SimpleKeyGenerator::new); // 默认基于 cacheManager 构造 SimpleCacheResolver // 至此,cacheResolver 有可能还是 null this.cacheResolver = new SingletonSupplier<>(cacheResolver, () -> SimpleCacheResolver.of(SupplierUtils.resolve(cacheManager))); } @Override public void afterSingletonsInstantiated() { if (getCacheResolver() == null) { try { setCacheManager(this.beanFactory.getBean(CacheManager.class)); } // ... } this.initialized = true; }
首先这里是一些缓存操作属性的定义,可以理解为默认的对象属性指定了 KeyGenerator 的默认实例是 SimpleKeyGenerator,之前的章节已经了解过之前了解 ProxyCachingConfiguration 配置类时了解过缓存属性可以基于 CachingConfigurer 类进行自定义配置,这里就是由 configure 方法处理:
CacheErrorHandler 未提供自定义配置时默认实例为 SimpleCacheErrorHandlerKeyGenerator 未提供自定义配置时默认实例为 SimpleKeyGeneratorcacheResolver 未提供自定义配置时默认实例为基于自定义 cacheManager 的 SimpleCacheResolver,当然这里如果也没有提供 cacheManager 那就是 null 了,具体细节可见 SupplierUtils SimpleCacheResolver#of 的处理 本类还是一个 SmartInitializingSingleton,因此容器管理下会执行 afterSingletonsInstantiated,此处支持在 cacheResolver 为 null 时尝试从容器中获取 cacheManager 并基于此创建 SimpleCacheResolver,如果此处依然无法创建 cacheResolver 则抛出异常,最后标识 initialized = true 2 - 从 execute 方法入手
@Nullable
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
if (this.initialized) {
Class> targetClass = getTargetClass(target);
// 获取 CacheOperationSource,此处就是 AnnotationCacheOperationSource 了
CacheOperationSource cacheOperationSource = getCacheOperationSource();
if (cacheOperationSource != null) {
// 或许对应方法的所有 CacheOperation
Collection operations = cacheOperationSource.getCacheOperations(method, targetClass);
if (!CollectionUtils.isEmpty(operations)) {
// 基于 CacheOperation 集合创建的 CacheOperationContexts 执行 execute 方法
return execute(invoker, method,
new CacheOperationContexts(operations, method, args, target, targetClass));
}
}
}
// 如果不在容器下管理此单例的话,这里就不执行缓存操作了
return invoker.invoke();
}
CacheInterceptor 的 invoke 方法是委托到这里的,即整个缓存切面的执行逻辑在这里实现先基于 CacheOperationSource(这里就是 AnnotationCacheOperationSource)获取目标方法上的所有 CacheOperationSources然后基于这些 CacheOperationSources 创建对应的 CacheOperationContexts 进而继续往下执行 3 - CacheOperationContexts
private class CacheOperationContexts {
// MultiValueMap: Spring 提供的一个可以重复同一个 key 的 Map
private final MultiValueMap, CacheOperationContext> contexts;
// 当前缓存操作是否需要同步执行
private final boolean sync;
public CacheOperationContexts(Collection extends CacheOperation> operations, Method method,
Object[] args, Object target, Class> targetClass) {
// 基于传入的 CacheOperation 集合构造对应的 CacheOperationContexts
this.contexts = new linkedMultiValueMap<>(operations.size());
for (CacheOperation op : operations) {
this.contexts.add(op.getClass(), getOperationContext(op, method, args, target, targetClass));
}
// 推断当前缓存操作是否需要同步执行
this.sync = determineSyncFlag(method);
}
// ...
// 推断是否同步执行
private boolean determineSyncFlag(Method method) {
// 同步操作只支持 CacheableOperation,如果没有那就是不需要同步
List cacheOperationContexts = this.contexts.get(CacheableOperation.class);
if (cacheOperationContexts == null) {
return false;
}
boolean syncEnabled = false;
for (CacheOperationContext cacheOperationContext : cacheOperationContexts) {
if (((CacheableOperation) cacheOperationContext.getOperation()).isSync()) {
syncEnabled = true;
break;
}
}
if (syncEnabled) {
// 多个 contexts 意味多种缓存操作,不支持同步执行
if (this.contexts.size() > 1) {
throw new IllegalStateException(
"...");
}
// 也不支持多个 @Cacheable(sync=true) 并行
if (cacheOperationContexts.size() > 1) {
throw new IllegalStateException(
"...");
}
// @Cacheable(sync=true) 操作也不支持同时指定多个 cacheName
CacheOperationContext cacheOperationContext = cacheOperationContexts.iterator().next();
CacheableOperation operation = (CacheableOperation) cacheOperationContext.getOperation();
if (cacheOperationContext.getCaches().size() > 1) {
throw new IllegalStateException(
"...");
}
// 缓存操作不支持指定 unless 属性
if (StringUtils.hasText(operation.getUnless())) {
throw new IllegalStateException(
"...");
}
return true;
}
return false;
}
}
之前的章节了解过缓存操作执行上下文相关的 CacheOperationInvocationContext 接口及其内部类实现 CacheOperationContext,这里的 CacheOperationContexts 是对 CacheOperationContext 的一层封装CacheOperationContexts 为目标方法上每种操作维护对应的一组 CacheOperationContexts,毕竟同一个缓存操作注解可以重复添加(但这样不支持 sync 同步属性)提供 determineSyncFlag 方法用来推断当前缓存操作是否需要同步执行,这里印证了之前对 sync 属性的定义:
它只适用于 CacheableOperation 即对应 @Cacheable 注解不支持与其他缓存操作混用不支持 @Cacheable 的合并对唯一的 @Cacheable 也不支持指定多个 cacheName同步操作时不支持 unless 属性 4 - getOperationContext
protected CacheOperationContext getOperationContext(
CacheOperation operation, Method method, Object[] args, Object target, Class> targetClass) {
// 构造目标方法目标操作上的 CacheOperationmetadata
CacheOperationmetadata metadata = getCacheOperationmetadata(operation, method, targetClass);
return new CacheOperationContext(metadata, args, target);
}
protected CacheOperationmetadata getCacheOperationmetadata(
CacheOperation operation, Method method, Class> targetClass) {
CacheOperationCacheKey cacheKey = new CacheOperationCacheKey(operation, method, targetClass);
// 先从缓存中获取,获取不到就创建
CacheOperationmetadata metadata = this.metadataCache.get(cacheKey);
if (metadata == null) {
KeyGenerator operationKeyGenerator;
if (StringUtils.hasText(operation.getKeyGenerator())) {
operationKeyGenerator = getBean(operation.getKeyGenerator(), KeyGenerator.class);
}
else {
operationKeyGenerator = getKeyGenerator();
}
CacheResolver operationCacheResolver;
if (StringUtils.hasText(operation.getCacheResolver())) {
operationCacheResolver = getBean(operation.getCacheResolver(), CacheResolver.class);
}
else if (StringUtils.hasText(operation.getCacheManager())) {
CacheManager cacheManager = getBean(operation.getCacheManager(), CacheManager.class);
operationCacheResolver = new SimpleCacheResolver(cacheManager);
}
else {
operationCacheResolver = getCacheResolver();
}
// 基于这些属性创建 CacheOperationmetadata
metadata = new CacheOperationmetadata(operation, method, targetClass,
operationKeyGenerator, operationCacheResolver);
this.metadataCache.put(cacheKey, metadata);
}
return metadata;
}
这里是构造 CacheOperation 对应的 CacheOperationContext,核心是构造 CacheOperationmetadata,即缓存操作相关的元数据其中创建 CacheOperationmetadata 时:
会优先使用注解上指定的 keyGenerator:从容器中获取对应 bean 实例同样地也会优先使用基于注解指定的 cacheResolver cacheManager 来构造对应的 cacheResolver至此我们大致可以排列配置的优先级:
注解上指定的配置优先级最高其次是 CacheConfigurer 上指定的配置最后是缺省配置,比如 SimpleKeyGenerator SimpleCacheErrorHandler 5 - execute
@Nullable
private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
// 如果当前方法要进行同步缓存操作
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, handleSynchronizedGet(invoker, key, cache));
}
catch (Cache.ValueRetrievalException ex) {
// ...
}
}
else {
// condition 不通过就直接执行目标方法了
return invokeOperation(invoker);
}
}
// 如果非同步操作
// 先执行属性 beforeInvocation = true 的 CacheEvictOperation
processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
CacheOperationexpressionevaluator.NO_RESULT);
// 获取可以找到的第一个缓存值
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
List cachePutRequests = new ArrayList<>();
// 如果没有命中缓存,则此时 CacheableOperation 就相当于 CachePutOperation 了
if (cacheHit == null) {
collectPutRequests(contexts.get(CacheableOperation.class),
CacheOperationexpressionevaluator.NO_RESULT, cachePutRequests);
}
Object cachevalue;
Object returnValue;
if (cacheHit != null && !hasCachePut(contexts)) {
// If there are no put requests, just use the cache hit
cachevalue = cacheHit.get();
returnValue = wrapCachevalue(method, cachevalue);
}
else {
returnValue = invokeOperation(invoker);
cachevalue = unwrapReturnValue(returnValue);
}
// 把所有的 CachePutOperation 合并起来(@Cacheable 和 @CachePut)
collectPutRequests(contexts.get(CachePutOperation.class), cachevalue, cachePutRequests);
// 使用最终的缓存值 cachevalue 执行 doPut 操作
for (CachePutRequest cachePutRequest : cachePutRequests) {
cachePutRequest.apply(cachevalue);
}
// 最后执行 beforeInvocation = false 的剔除缓存操作
processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cachevalue);
// 方法的真实返回值
return returnValue;
}
这个方法就是 Spring Cache 的实现逻辑了:
- 首先如果之前构造 CacheOperationContexts 推断目标缓存方法需要同步执行时,会最终依赖 Cache#get(Object key, Callable
缓存命中时:cacheval 即命中的值,retuanVal 有必要的话基于 cacheval 包装成 Optional缓存未命中时:retuanVal 即目标方法的执行结果,cacheval 有必要的话从 Optional 包装取出 收集所有的 CachePutRequest,这里包括了两种:
- 未命中缓存的 CacheableOperationCachePutOperation
public abstract class AbstractCacheInvoker {
protected SingletonSupplier errorHandler;
// 默认 SimpleCacheErrorHandler
protected AbstractCacheInvoker() {
this.errorHandler = SingletonSupplier.of(SimpleCacheErrorHandler::new);
}
// ...
@Nullable
protected Cache.ValueWrapper doGet(Cache cache, Object key) {
try {
return cache.get(key);
}
catch (RuntimeException ex) {
getErrorHandler().handleCacheGetError(ex, cache, key);
return null;
}
}
protected void doPut(Cache cache, Object key, @Nullable Object result) {
try {
cache.put(key, result);
}
catch (RuntimeException ex) {
getErrorHandler().handleCachePutError(ex, cache, key, result);
}
}
protected void doEvict(Cache cache, Object key, boolean immediate) {
try {
if (immediate) {
// 立即剔除
cache.evictIfPresent(key);
}
else {
// 不保证实时性
cache.evict(key);
}
}
catch (RuntimeException ex) {
getErrorHandler().handleCacheEvictError(ex, cache, key);
}
}
protected void doClear(Cache cache, boolean immediate) {
try {
if (immediate) {
// 立即清除缓存
cache.invalidate();
}
else {
// 不保证实时性
cache.clear();
}
}
catch (RuntimeException ex) {
getErrorHandler().handleCacheClearError(ex, cache);
}
}
}
顶层基类 AbstractCacheInvoker:
封装整个 Spring Cache 对底层缓存操作的基础方法 doGet doPut doEvict doClear操作过程中的异常由 CacheErrorHandler 接口处理,默认是 Spring 提供的唯一实现 SimpleCacheErrorHandler:直接抛出对应异常 总结
这段太干了,但是读都读了就尽可能全都贴上来,抛开实现的细节逻辑,我认为至少有以下几点直观收益:
清楚的理解了缓存操作属性的配置方式和优先级原理:注解上指定的属性 > CacheConfigurer 指定的属性 > 缺省属性,因此可以更加合理的编写配置类CacheOperationContexts 类的设计很有意思,优雅的管理了 method -> CacheOperation -> CacheOperationContext 的关系CacheInterceptor CacheAspectSupport AbstractCacheInvoker 类层级的设计:
CacheInterceptor:站在 AOP 角度专注于 Cache Interceptor 的实现CacheAspectSupport:负责实现核心的 Spring Cache 逻辑AbstractCacheInvoker:提供对底层缓存的操作方法 等等其他,其实主要用心看,值得学习的地方是很多的
上一篇:【Spring Cache】五 从 @EnableCaching 了解 Spring Cache 实现流程
下一篇:【Spring Cache】七 Spring Cache 流程总结



