哈哈哈,这个类里面定义了AOP的三大要素:advisor、interceptor和Pointcut,只是Pointcut是在BeanFactoryCacheOperationSourceAdvisor内部定义的 。
文章插图
另外定义了CacheOperationSource类,该类封装了cache方法签名注解的解析工作,形成CacheOperation的集合 。它的构造方法会实例化SpringCacheAnnotationParser,现在看看这个类的parseCacheAnnotations方法 。
private Collection<CacheOperation> parseCacheAnnotations(DefaultCacheConfig cachingConfig, AnnotatedElement ae, boolean localOnly) {Collection<CacheOperation> ops = null;//找@cacheable注解方法Collection<Cacheable> cacheables = (localOnly ? AnnotatedElementUtils.getAllMergedAnnotations(ae, Cacheable.class) :AnnotatedElementUtils.findAllMergedAnnotations(ae, Cacheable.class));if (!cacheables.isEmpty()) {ops = lazyInit(null);for (Cacheable cacheable : cacheables) {ops.add(parseCacheableAnnotation(ae, cachingConfig, cacheable));}}//找@cacheEvict注解的方法Collection<CacheEvict> evicts = (localOnly ? AnnotatedElementUtils.getAllMergedAnnotations(ae, CacheEvict.class) :AnnotatedElementUtils.findAllMergedAnnotations(ae, CacheEvict.class));if (!evicts.isEmpty()) {ops = lazyInit(ops);for (CacheEvict evict : evicts) {ops.add(parseEvictAnnotation(ae, cachingConfig, evict));}}//找@cachePut注解的方法Collection<CachePut> puts = (localOnly ? AnnotatedElementUtils.getAllMergedAnnotations(ae, CachePut.class) :AnnotatedElementUtils.findAllMergedAnnotations(ae, CachePut.class));if (!puts.isEmpty()) {ops = lazyInit(ops);for (CachePut put : puts) {ops.add(parsePutAnnotation(ae, cachingConfig, put));}} //找@Caching注解的方法Collection<Caching> cachings = (localOnly ? AnnotatedElementUtils.getAllMergedAnnotations(ae, Caching.class) :AnnotatedElementUtils.findAllMergedAnnotations(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;}
我们看到这个类会解析@cacheable、@cacheEvict、@cachePut 和 @Caching注解的参数,封装到CacheOperation集合中 。
此外,spring cache 功能的关键就是上面的拦截器:CacheInterceptor,它最终会调到这个方法:
@Nullableprivate Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {// Special handling of synchronized invocationif (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, () -> 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 methodreturn invokeOperation(invoker);}}// 执行@CacheEvict的逻辑,这里是当beforeInvocation为true时清缓存processCacheEvicts(contexts.get(CacheEvictOperation.class), true,CacheOperationExpressionEvaluator.NO_RESULT);// 获取命中的缓存对象Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));//如果没有命中,则生成一个put的请求List<CachePutRequest> cachePutRequests = new LinkedList<>();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 hitcacheValue = https://www.isolves.com/it/cxkf/kj/2020-09-27/cacheHit.get();returnValue = wrapCacheValue(method, cacheValue);}else {// 如果没有获得缓存对象,则调用业务方法获得返回对象,这是关键代码returnValue = invokeOperation(invoker);cacheValue = unwrapReturnValue(returnValue);}// 收集@CachePuts数据collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);// 执行cachePut或没有命中的Cacheable请求,将返回对象放到缓存中for (CachePutRequest cachePutRequest : cachePutRequests) {cachePutRequest.apply(cacheValue);}// 执行@CacheEvict的逻辑,这里是当beforeInvocation为false时清缓存processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);return returnValue;}
也行有些朋友看到这里会有一个疑问:
既然spring cache的增删改查都有了,为啥还要 @Caching 注解呢?
推荐阅读
- 如何使用软路由实现宽带加速,免费让300M宽带变600M
- 使用 Python 自动发送 QQ 消息
- 人人都能掌握的Chrome使用技巧
- Android Hawk框架使用介绍
- 使用Docker来构建、运行、发布微服务
- 使用Excel来制作文件管理目录
- RFM模型升级,使用Excel完成全自动分析
- Springboot 实现数据库备份还原
- 组策略 WindowsServer2008的使用详解
- Docker下使用disconf:细说demo开发