spring cache定义的接口
如下图,涉及到的操作有get、put、evict,对应于查询、更新、清除缓存
对应的注解为cacheable、cacheevict、cacheput操作,可以查看源码分析注解的字段了解注解的用法
参考:
http://blog.csdn.net/sanjay_f/article/details/47372967
https://www.cnblogs.com/fashflying/p/6908028.html
SpEL上下文数据
spring cache支持SpEL表达式
methodName
root对象
当前被调用的方法名
root.methodName
method
root对象
当前被调用的方法
root.method.name
target
root对象
当前被调用的目标对象
root.target
targetClass
root对象
当前被调用的目标对象类
root.targetClass
args
root对象
当前被调用的方法的参数列表
root.args[0]
caches
root对象
当前方法调用使用的缓存列表(如@Cacheable(value={"cache1", "cache2"})),则有两个cache
root.caches[0].name
argument name
执行上下文
当前被调用的方法的参数,如findById(Long id),我们可以通过#id拿到参数
user.id
result
执行上下文
方法执行后的返回值(仅当方法执行之后的判断有效,如‘unless’,'cache evict'的beforeInvocation=false)
result
通过这些数据我们可能实现比较复杂的缓存逻辑了,后边再来介绍。
execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments());
根据 类 + 方法 ,获取定义的缓存操作,构建缓存上下文
缓存的执行流程
1、首先执行@CacheEvict(如果beforeInvocation=true且condition 通过),如果allEntries=true,则清空所有
2、接着收集@Cacheable(如果condition 通过,且key对应的数据不在缓存),放入cachePutRequests(也就是说如果cachePutRequests为空,则数据在缓存中)
3、如果cachePutRequests为空且没有@CachePut操作,那么将查找@Cacheable的缓存,否则result=缓存数据(也就是说只要当没有cache put请求时才会查找缓存)
4、如果没有找到缓存,那么调用实际的API,把结果放入result
5、如果有@CachePut操作(如果condition 通过),那么放入cachePutRequests
6、执行cachePutRequests,将数据写入缓存(unless为空或者unless解析结果为false);
7、执行@CacheEvict(如果beforeInvocation=false 且 condition 通过),如果allEntries=true,则清空所有
// Process any early evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
CacheOperationExpressionEvaluator.NO_RESULT);
// Check if we have a cached item matching the conditions
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
// 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 {
// Invoke the method if we don't have a cache hit
returnValue = invokeOperation(invoker);
cacheValue = unwrapReturnValue(returnValue);
}
// Collect any explicit @CachePuts
collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);
// Process any collected put requests, either from @CachePut or a @Cacheable miss
for (CachePutRequest cachePutRequest : cachePutRequests) {
cachePutRequest.apply(cacheValue);
}
// Process any late evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);
如何定义自己的缓存管理器CacheManager
spring cache的CacheManager的体系结构如下
默认提供了Ehcache和JCache的支持,并且缓存还支持事务(事务回退缓存回退),如果自定义缓存可以选择继承其中的某一个,只需要实现其中一个抽象方法,将实现了cache接口的缓存注入到缓存管理器即可