共计 12141 个字符,预计需要花费 31 分钟才能阅读完成。
Spring cache 是一个缓存 API 层,封装了对多种缓存的通用操作,能够借助注解不便地为程序增加缓存性能。
常见的注解有 @Cacheable、@CachePut、@CacheEvict,有没有想过背地的原理是什么?楼主带着疑难,浏览完 Spring cache 的源码后,做一个简要总结。
先说论断,外围逻辑在 CacheAspectSupport 类 ,封装了所有的缓存操作的主体逻辑,上面具体介绍。
题外话:如何浏览开源代码?
有 2 种办法,能够联合起来应用:
- 动态代码浏览 :查找要害类、办法的 usage 之处,纯熟应用 find usages 性能,找到所有相干的类、办法,动态剖析外围逻辑的执行过程,一步步追根问底,直至建设全貌
- 运行时 debug:在要害办法上加上断点,并且写一个单元测试调用类库 / 框架,纯熟应用 step into/step over/resume 来动态分析代码的执行过程
外围类图
如图所示,能够分成以下几类 class:
- Cache、CacheManager:Cache 形象了缓存的通用操作,如 get、put,而 CacheManager 是 Cache 的汇合,之所以须要多个 Cache 对象,是因为须要多种缓存生效工夫、缓存条目下限等
- CacheInterceptor、CacheAspectSupport、AbstractCacheInvoker:CacheInterceptor 是一个 AOP 办法拦截器,在办法前后做额定的逻辑,也即查问缓存、写入缓存等,它继承了 CacheAspectSupport(缓存操作的主体逻辑)、AbstractCacheInvoker(封装了对 Cache 的读写)
- CacheOperation、AnnotationCacheOperationSource、SpringCacheAnnotationParser:CacheOperation 定义了缓存操作的缓存名字、缓存 key、缓存条件 condition、CacheManager 等,AnnotationCacheOperationSource 是一个获取缓存注解对应 CacheOperation 的类,而 SpringCacheAnnotationParser 是真正解析注解的类,解析后会封装成 CacheOperation 汇合供 AnnotationCacheOperationSource 查找
源码剖析(带正文解释)
上面对 Spring cache 源码做剖析,带正文解释,只摘录外围代码片段。
1、解析注解
首先看看注解是如何解析的。注解只是一个标记,要让它真正工作起来,须要对注解做解析操作,并且还要有对应的理论逻辑。
SpringCacheAnnotationParser:负责解析注解,返回 CacheOperation 汇合
public class SpringCacheAnnotationParser implements CacheAnnotationParser, Serializable {
// 解析类级别的缓存注解
@Override
public Collection<CacheOperation> parseCacheAnnotations(Class<?> type) {DefaultCacheConfig defaultConfig = getDefaultCacheConfig(type);
return parseCacheAnnotations(defaultConfig, type);
}
// 解析办法级别的缓存注解
@Override
public Collection<CacheOperation> parseCacheAnnotations(Method method) {DefaultCacheConfig defaultConfig = getDefaultCacheConfig(method.getDeclaringClass());
return parseCacheAnnotations(defaultConfig, method);
}
// 解析缓存注解
private Collection<CacheOperation> parseCacheAnnotations(DefaultCacheConfig cachingConfig, AnnotatedElement ae) {
Collection<CacheOperation> ops = null;
// 解析 @Cacheable 注解
Collection<Cacheable> cacheables = AnnotatedElementUtils.getAllMergedAnnotations(ae, Cacheable.class);
if (!cacheables.isEmpty()) {ops = lazyInit(ops);
for (Cacheable cacheable : cacheables) {ops.add(parseCacheableAnnotation(ae, cachingConfig, cacheable));
}
}
// 解析 @CacheEvict 注解
Collection<CacheEvict> evicts = AnnotatedElementUtils.getAllMergedAnnotations(ae, CacheEvict.class);
if (!evicts.isEmpty()) {ops = lazyInit(ops);
for (CacheEvict evict : evicts) {ops.add(parseEvictAnnotation(ae, cachingConfig, evict));
}
}
// 解析 @CachePut 注解
Collection<CachePut> puts = AnnotatedElementUtils.getAllMergedAnnotations(ae, CachePut.class);
if (!puts.isEmpty()) {ops = lazyInit(ops);
for (CachePut put : puts) {ops.add(parsePutAnnotation(ae, cachingConfig, put));
}
}
// 解析 @Caching 注解
Collection<Caching> cachings = AnnotatedElementUtils.getAllMergedAnnotations(ae, Caching.class);
if (!cachings.isEmpty()) {ops = lazyInit(ops);
for (Caching caching : cachings) {Collection<CacheOperation> cachingOps = parseCachingAnnotation(ae, cachingConfig, caching);
if (cachingOps != null) {ops.addAll(cachingOps);
}
}
}
return ops;
}
AnnotationCacheOperationSource:调用 SpringCacheAnnotationParser 获取注解对应 CacheOperation
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implements Serializable {
// 查找类级别的 CacheOperation 列表
@Override
protected Collection<CacheOperation> findCacheOperations(final Class<?> clazz) {return determineCacheOperations(new CacheOperationProvider() {
@Override
public Collection<CacheOperation> getCacheOperations(CacheAnnotationParser parser) {return parser.parseCacheAnnotations(clazz);
}
});
}
// 查找办法级别的 CacheOperation 列表
@Override
protected Collection<CacheOperation> findCacheOperations(final Method method) {return determineCacheOperations(new CacheOperationProvider() {
@Override
public Collection<CacheOperation> getCacheOperations(CacheAnnotationParser parser) {return parser.parseCacheAnnotations(method);
}
});
}
}
AbstractFallbackCacheOperationSource:AnnotationCacheOperationSource 的父类,实现了获取 CacheOperation 的通用逻辑
public abstract class AbstractFallbackCacheOperationSource implements CacheOperationSource {
/**
* Cache of CacheOperations, keyed by method on a specific target class.
* <p>As this base class is not marked Serializable, the cache will be recreated
* after serialization - provided that the concrete subclass is Serializable.
*/
private final Map<Object, Collection<CacheOperation>> attributeCache =
new ConcurrentHashMap<Object, Collection<CacheOperation>>(1024);
// 依据 Method、Class 反射信息,获取对应的 CacheOperation 列表
@Override
public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {if (method.getDeclaringClass() == Object.class) {return null;}
Object cacheKey = getCacheKey(method, targetClass);
Collection<CacheOperation> cached = this.attributeCache.get(cacheKey);
// 因解析反射信息较耗时,所以用 map 缓存,防止反复计算
// 如在 map 里已记录,间接返回
if (cached != null) {return (cached != NULL_CACHING_ATTRIBUTE ? cached : null);
}
// 否则做一次计算,而后写入 map
else {Collection<CacheOperation> cacheOps = computeCacheOperations(method, targetClass);
if (cacheOps != null) {if (logger.isDebugEnabled()) {logger.debug("Adding cacheable method'" + method.getName() + "'with attribute:" + cacheOps);
}
this.attributeCache.put(cacheKey, cacheOps);
}
else {this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
}
return cacheOps;
}
}
// 计算缓存操作列表,优先用 target 代理类的办法上的注解,如果不存在则其次用 target 代理类,再次用原始类的办法,最初用原始类
private Collection<CacheOperation> computeCacheOperations(Method method, Class<?> targetClass) {
// Don't allow no-public methods as required.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {return null;}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
// If we are dealing with method with generic parameters, find the original method.
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
// 调用 findCacheOperations(由子类 AnnotationCacheOperationSource 实现),最终通过 SpringCacheAnnotationParser 来解析
// First try is the method in the target class.
Collection<CacheOperation> opDef = findCacheOperations(specificMethod);
if (opDef != null) {return opDef;}
// Second try is the caching operation on the target class.
opDef = findCacheOperations(specificMethod.getDeclaringClass());
if (opDef != null && ClassUtils.isUserLevelMethod(method)) {return opDef;}
if (specificMethod != method) {
// Fallback is to look at the original method.
opDef = findCacheOperations(method);
if (opDef != null) {return opDef;}
// Last fallback is the class of the original method.
opDef = findCacheOperations(method.getDeclaringClass());
if (opDef != null && ClassUtils.isUserLevelMethod(method)) {return opDef;}
}
return null;
}
2、逻辑执行
以 @Cacheable 背地的逻辑为例。预期是先查缓存,如果缓存命中了就间接应用缓存值,否则执行业务逻辑,并把后果写入缓存。
ProxyCachingConfiguration:是一个配置类,用于生成 CacheInterceptor 类和 CacheOperationSource 类的 Spring bean
CacheInterceptor:是一个 AOP 办法拦截器,它通过 CacheOperationSource 获取第 1 步解析注解的 CacheOperation 后果(如缓存名字、缓存 key、condition 条件),实质上是拦挡原始办法的执行,在之前、之后减少逻辑
// 外围类,缓存拦截器
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {
// 拦挡原始办法的执行,在之前、之后减少逻辑
@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:缓存切面反对类,是 CacheInterceptor 的父类,封装了所有的缓存操作的主体逻辑
次要流程如下:
- 通过 CacheOperationSource,获取所有的 CacheOperation 列表
- 如果有 @CacheEvict 注解、并且标记为在调用前执行,则做删除 / 清空缓存的操作
- 如果有 @Cacheable 注解,查问缓存
- 如果缓存未命中(查问后果为 null),则新增到 cachePutRequests,后续执行原始办法后会写入缓存
- 缓存命中时,应用缓存值作为后果;缓存未命中、或有 @CachePut 注解时,须要调用原始办法,应用原始办法的返回值作为后果
- 如果有 @CachePut 注解,则新增到 cachePutRequests
- 如果缓存未命中,则把查问后果值写入缓存;如果有 @CachePut 注解,也把办法执行后果写入缓存
- 如果有 @CacheEvict 注解、并且标记为在调用后执行,则做删除 / 清空缓存的操作
// 外围类,缓存切面反对类,封装了所有的缓存操作的主体逻辑
public abstract class CacheAspectSupport extends AbstractCacheInvoker
implements BeanFactoryAware, InitializingBean, SmartInitializingSingleton {
// CacheInterceptor 调父类的该办法
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);
// 通过 CacheOperationSource,获取所有的 CacheOperation 列表
Collection<CacheOperation> operations = getCacheOperationSource().getCacheOperations(method, targetClass);
if (!CollectionUtils.isEmpty(operations)) {
// 持续调一个 private 的 execute 办法执行
return execute(invoker, method, new CacheOperationContexts(operations, method, args, target, targetClass));
}
}
// 如果 spring bean 未初始化实现,则间接调用原始办法。相当于原始办法没有缓存性能。return invoker.invoke();}
private 的 execute 办法
private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
// Special handling of synchronized invocation
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, cache.get(key, new Callable<Object>() {
@Override
public Object call() throws Exception {return unwrapReturnValue(invokeOperation(invoker));
}
}));
}
catch (Cache.ValueRetrievalException ex) {
// The invoker wraps any Throwable in a ThrowableWrapper instance so we
// can just make sure that one bubbles up the stack.
throw (CacheOperationInvoker.ThrowableWrapper) ex.getCause();}
}
else {
// No caching required, only call the underlying method
return invokeOperation(invoker);
}
}
// 如果有 @CacheEvict 注解、并且标记为在调用前执行,则做删除 / 清空缓存的操作
// Process any early evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
CacheOperationExpressionEvaluator.NO_RESULT);
// 如果有 @Cacheable 注解,查问缓存
// Check if we have a cached item matching the conditions
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
// 如果缓存未命中(查问后果为 null),则新增到 cachePutRequests,后续执行原始办法后会写入缓存
// Collect puts from any @Cacheable miss, if no cached item is found
List<CachePutRequest> cachePutRequests = new LinkedList<CachePutRequest>();
if (cacheHit == null) {collectPutRequests(contexts.get(CacheableOperation.class),
CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
}
Object cacheValue;
Object returnValue;
if (cacheHit != null && cachePutRequests.isEmpty() && !hasCachePut(contexts)) {
// 缓存命中的状况,应用缓存值作为后果
// If there are no put requests, just use the cache hit
cacheValue = cacheHit.get();
returnValue = wrapCacheValue(method, cacheValue);
}
else {
// 缓存未命中、或有 @CachePut 注解的状况,须要调用原始办法
// Invoke the method if we don't have a cache hit
// 调用原始办法,失去后果值
returnValue = invokeOperation(invoker);
cacheValue = unwrapReturnValue(returnValue);
}
// 如果有 @CachePut 注解,则新增到 cachePutRequests
// Collect any explicit @CachePuts
collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);
// 如果缓存未命中,则把查问后果值写入缓存;如果有 @CachePut 注解,也把办法执行后果写入缓存
// Process any collected put requests, either from @CachePut or a @Cacheable miss
for (CachePutRequest cachePutRequest : cachePutRequests) {cachePutRequest.apply(cacheValue);
}
// 如果有 @CacheEvict 注解、并且标记为在调用后执行,则做删除 / 清空缓存的操作
// Process any late evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);
return returnValue;
}
private Cache.ValueWrapper findCachedItem(Collection<CacheOperationContext> contexts) {
Object result = CacheOperationExpressionEvaluator.NO_RESULT;
for (CacheOperationContext context : contexts) {
// 如果满足 condition 条件,才查问缓存
if (isConditionPassing(context, result)) {
// 生成缓存 key,如果注解中指定了 key,则依照 Spring 表达式解析,否则应用 KeyGenerator 类生成
Object key = generateKey(context, result);
// 依据缓存 key,查问缓存值
Cache.ValueWrapper cached = findInCaches(context, key);
if (cached != null) {return cached;}
else {if (logger.isTraceEnabled()) {logger.trace("No cache entry for key'" + key + "'in cache(s)" + context.getCacheNames());
}
}
}
}
return null;
}
private Cache.ValueWrapper findInCaches(CacheOperationContext context, Object key) {for (Cache cache : context.getCaches()) {
// 调用父类 AbstractCacheInvoker 的 doGet 办法,查问缓存
Cache.ValueWrapper wrapper = doGet(cache, key);
if (wrapper != null) {if (logger.isTraceEnabled()) {logger.trace("Cache entry for key'" + key + "'found in cache'" + cache.getName() + "'");
}
return wrapper;
}
}
return null;
}
AbstractCacheInvoker:CacheAspectSupport 的父类,封装了最终查问 Cache 接口的逻辑
public abstract class AbstractCacheInvoker {
// 最终查问缓存的办法
protected Cache.ValueWrapper doGet(Cache cache, Object key) {
try {
// 调用 Spring Cache 接口的查询方法
return cache.get(key);
}
catch (RuntimeException ex) {getErrorHandler().handleCacheGetError(ex, cache, key);
return null; // If the exception is handled, return a cache miss
}
}
}
正文完