Spring Cache 源码分析 (4) - 缓存拦截器( CacheInterceptor)
缓存拦截器的实现
这一篇我们讲讲SpringCache对方法的拦截器实现,也就是CacheInterceptor。在使用SpringCache我们会比较关注的问题,为什么对一个方法使用@CachePut注解后,就可以达到缓存的效果呢?下面我们将揭开这层面纱。Spring Cache实现对方法的拦截功能,是由CacheInterceptor提供的。下面直接看看CacheInterceptor是怎么做的呢?
CacheInterceptor实现了MethodInterceptor接口,在Spring AOP中,MethodInterceptor的功能是做方法拦截。现在应该明白,为什么使用@CachePut等注解后可以实现缓存操作,因为方法被拦截处理了。CacheInterceptor的实现很简单,啥都不用啰说了,先看看代码实现。
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {
/*
*被拦截的方法都会调用invoke方法,不懂的可以先看看Spring AOP。
*/
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
//这里就是对执行方法调用的一次封装,主要是为了处理对异常的包装。
CacheOperationInvoker aopAllianceInvoker = new CacheOperationInvoker() {
@Override
public Object invoke() {
try {
return invocation.proceed();
}
catch (Throwable ex) {
throw new ThrowableWrapper(ex);
}
}
};
try {
//真正地去处理缓存操作的执行,很显然这是父类的方法,所以我们要到父类CacheAspectSupport中去看看。
return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments());
}
catch (CacheOperationInvoker.ThrowableWrapper th) {
throw th.getOriginal();
}
}
}
下面,我们再看看CacheAspectSupport#execute(...)这个方法中具体怎么进行缓存操作的。
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
//标志Spring加载元素是否都准备好了,是否可以执行了
if (this.initialized) {
Class<?> targetClass = getTargetClass(target);
//这里使用的就是CacheOperationSource,来获取执行方法上所有的缓存操作集合。如果有缓存操作则执行到execute(...),如果没有就执行invoker.invoke()直接调用执行方法了。
Collection<CacheOperation> operations = getCacheOperationSource().getCacheOperations(method, targetClass);
if (!CollectionUtils.isEmpty(operations)) {
return execute(invoker, new CacheOperationContexts(operations, method, args, target, targetClass));
}
}
return invoker.invoke();
}
在上面的代码中出现了CacheOperationContexts对象,这个对象只是为了便于获取每种具体缓存操作集合。我们知道所有的缓存操作CachePutOperation、CacheableOperation、CacheEvictOperation都存放在operations这个集合中,不便于获取具体的缓存操作,所以封装成了缓存操作上下文CacheOperationContexts这个类。接下来,我们继续看看核心代码,庐山真面目即将揭晓。先罗列一下@CachePut、@Cacheable、@CacheEvict的功能,再来看看代码是怎么实现的。
- @CachePut -- 执行方法后,将方法返回结果存放到缓存中。不管有没有缓存过,执行方法都会执行,并缓存返回结果(unless可以否决进行缓存)。(当然,这里说的缓存都要满足condition条件&