SpringCache源码| Spring Cache的AOP实现原理
1. 简述
Spring Cache是通过AOP面向切面编程的思想来对缓存的操作进行封装,通过拦截器对实现了Spring Cache注解的方法进行拦截,可以根据注解信息去完成相应的缓存操作。
2. CacheInterceptor拦截器
Spring Cache提供了一个缓存拦截器,负责拦截方法调用执行缓存逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable { public CacheInterceptor() { }
@Nullable public Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); CacheOperationInvoker aopAllianceInvoker = () -> { try { return invocation.proceed(); } catch (Throwable var2) { throw new ThrowableWrapper(var2); } };
try { return this.execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments()); } catch (ThrowableWrapper var5) { throw var5.getOriginal(); } } }
|
CacheIntercepto实现了MethodInterceptor,MethodInterceptor主要对方法进行拦截,查看MethodInterceptor的继承图,发现MethodInterceptor就是一个Advice,在Spring AOP的概念里面,Advice就是一个通知,通知封装了AOP的横切逻辑。由此来说CacheInterceptor作为一个通知,他里面肯定包含缓存操作的横切逻辑,能够处理方法调用前后的缓存操作。
2.1 查看父类的核心方法execute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Nullable protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) { if(this.initialized) { Class<?> targetClass = this.getTargetClass(target); CacheOperationSource cacheOperationSource = this.getCacheOperationSource(); if(cacheOperationSource != null) { Collection<CacheOperation> operations = cacheOperationSource.getCacheOperations(method, targetClass); if(!CollectionUtils.isEmpty(operations)) { return this.execute(invoker, method, new CacheAspectSupport.CacheOperationContexts(operations, method, args, target, targetClass)); } } }
return invoker.invoke(); }
|
这个方法的主要作用:
- 获取缓存操作集合CacheOperation
- 封装缓存操作上下文,并调用内部的execute方法
2.2 核心内部方法execute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| @Nullable private Object execute(CacheOperationInvoker invoker, Method method, CacheAspectSupport.CacheOperationContexts contexts) { if(contexts.isSynchronized()) { CacheAspectSupport.CacheOperationContext context = (CacheAspectSupport.CacheOperationContext)contexts.get(CacheableOperation.class).iterator().next(); if(this.isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) { Object key = this.generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT); Cache cache = (Cache)context.getCaches().iterator().next();
try { return this.wrapCacheValue(method, cache.get(key, () -> { return this.unwrapReturnValue(this.invokeOperation(invoker)); })); } catch (ValueRetrievalException var10) { throw (ThrowableWrapper)var10.getCause(); } } else { return this.invokeOperation(invoker); } } else { this.processCacheEvicts(contexts.get(CacheEvictOperation.class), true, CacheOperationExpressionEvaluator.NO_RESULT); ValueWrapper cacheHit = this.findCachedItem(contexts.get(CacheableOperation.class)); List<CacheAspectSupport.CachePutRequest> cachePutRequests = new LinkedList(); if(cacheHit == null) { this.collectPutRequests(contexts.get(CacheableOperation.class), CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests); }
Object cacheValue; Object returnValue;
if(cacheHit != null && !this.hasCachePut(contexts)) { cacheValue = cacheHit.get(); returnValue = this.wrapCacheValue(method, cacheValue); } else { returnValue = this.invokeOperation(invoker); cacheValue = this.unwrapReturnValue(returnValue); }
this.collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests); Iterator var8 = cachePutRequests.iterator();
while(var8.hasNext()) { CacheAspectSupport.CachePutRequest cachePutRequest = (CacheAspectSupport.CachePutRequest)var8.next(); cachePutRequest.apply(cacheValue); }
this.processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue); return returnValue; } }
|
如果不需要同步,该方法主要完成了以下的逻辑
- 处理BeforeInvocation = true的缓存删除操作
- 通过@Cacheable注解找到对应的缓存值。
- 如果没有找到对应的缓存数据,则将@Cacheable封装成CachePutRequest,标记为一个插入缓存的请求。
- 进行方法调用
- 将CachePut注解封装成CachePutRequest
- 遍历CachePutReqeust集合,将方法调用的返回值置入缓存中。
- 处理BeforeInvocation = false的缓存删除操作
梳理一下,这个方法里面包括三个注解的逻辑
@Cacheable
(1) 首先从缓存中找@Cacheable对应的缓存
(2) 如果缓存存在,则取出缓存值作为返回值
(3) 如果缓存不存在,则进行方法调用,获取返回值,并将返回值置入缓存
@CachePut
(1) 如果包含cachePut注解,则进行方法调用。
(2) 获取方法返回值,并置入缓存之中。
@CacheEvic
(1) 在方法调用签执行缓存删除操作。
(2) 在方法调用后执行缓存删除操作。
2.2.1 processCacheEvicts
我们来看看缓存删除的具体逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| private void processCacheEvicts(Collection<CacheAspectSupport.CacheOperationContext> contexts, boolean beforeInvocation, @Nullable Object result) { Iterator var4 = contexts.iterator();
while(var4.hasNext()) { CacheAspectSupport.CacheOperationContext context = (CacheAspectSupport.CacheOperationContext)var4.next(); CacheEvictOperation operation = (CacheEvictOperation)context.metadata.operation; if(beforeInvocation == operation.isBeforeInvocation() && this.isConditionPassing(context, result)) { this.performCacheEvict(context, operation, result); } }
}
private void performCacheEvict(CacheAspectSupport.CacheOperationContext context, CacheEvictOperation operation, @Nullable Object result) { Object key = null; Iterator var5 = context.getCaches().iterator();
while(var5.hasNext()) { Cache cache = (Cache)var5.next(); if(operation.isCacheWide()) { this.logInvalidating(context, operation, (Object)null); this.doClear(cache); } else { if(key == null) { key = this.generateKey(context, result); }
this.logInvalidating(context, operation, key); this.doEvict(cache, key); } }
}
|
2.2.2 findCachedItem(获取缓存数据)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| @Nullable private ValueWrapper findCachedItem(Collection<CacheAspectSupport.CacheOperationContext> contexts) { Object result = CacheOperationExpressionEvaluator.NO_RESULT; Iterator var3 = contexts.iterator();
while(var3.hasNext()) { CacheAspectSupport.CacheOperationContext context = (CacheAspectSupport.CacheOperationContext)var3.next(); if(this.isConditionPassing(context, result)) { Object key = this.generateKey(context, result); ValueWrapper cached = this.findInCaches(context, key); if(cached != null) { return cached; }
if(this.logger.isTraceEnabled()) { this.logger.trace("No cache entry for key '" + key + "' in cache(s) " + context.getCacheNames()); } } }
return null; }
@Nullable private ValueWrapper findInCaches(CacheAspectSupport.CacheOperationContext context, Object key) { Iterator var3 = context.getCaches().iterator();
Cache cache; ValueWrapper wrapper; do { if(!var3.hasNext()) { return null; } cache = (Cache)var3.next(); wrapper = this.doGet(cache, key); } while(wrapper == null);
if(this.logger.isTraceEnabled()) { this.logger.trace("Cache entry for key '" + key + "' found in cache '" + cache.getName() + "'"); }
return wrapper; }
|
2.2.3collectPutRequests(封装存储缓存的请求)
1 2 3 4 5 6 7 8 9 10 11 12 13
| private void collectPutRequests(Collection<CacheAspectSupport.CacheOperationContext> contexts, @Nullable Object result, Collection<CacheAspectSupport.CachePutRequest> putRequests) { Iterator var4 = contexts.iterator();
while(var4.hasNext()) { CacheAspectSupport.CacheOperationContext context = (CacheAspectSupport.CacheOperationContext)var4.next(); if(this.isConditionPassing(context, result)) { Object key = this.generateKey(context, result); putRequests.add(new CacheAspectSupport.CachePutRequest(context, key)); } }
}
|
3 总结
目前,关于Spring Cache的源码分析就告一段落了,总的来说,SpringCache的分析文章主要对缓存注解实现的源码做了一个简要的分析,目的是能够对缓存操作的AOP实现原理有一个清晰的认识。能够搞清楚Spring Cache是如何借助AOP的思想来实现如何简单、快捷且代码侵入低的缓存组件。由此我们可以借鉴这些思想和案例来丰富我们的阅历,以助于提高我们的技术水平,帮助我们能够实现类似的开源组件。