springboot @Cacheable 的实现原理

本文详细阐述了Spring Boot中@Cacheable的使用方法,并逐步揭示了其背后的AOP、动态代理和CacheInterceptor的工作原理。从@EnableCaching注解到实际的缓存操作,一步步解析了整个缓存生命周期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. springboot cache 的使用

  a.pom引入jar spring-boot-starter-cache
  b.启动类增加注解@EnableCaching
  c.需要缓存的方法增加注解 @Cacheable(cacheNames = "com:xxx",key = "''+#id")

图1
在这里插入图片描述

2. Cacheable 的实现原理猜测

实现原理是什么呢?脑海第一反应应该当然是大名鼎鼎是AOP、动态代理、Interceptor这些概念,那我们怎么去验证呢?

3. Cacheable 的实现原理验证

从调用该方法getById的入口打断点跟进去到了CglibAopProxy动态代理,看到了关键的代码获取Interceptor调用链

# DynamicAdvisedInterceptor.intercept 方法
 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

具体的Interceptor 如下图,果然有个一个和Cache相关的CacheInterceptor自此验证我们在第二部的猜测
图2在这里插入图片描述

4. 原理是怎么实现的呢?

a.继续第3步的源码往里面走看看Interceptor是从哪里获取到的,往下面走看到是通过advisor来获取缓存的Interceptor,如下图3
在这里插入图片描述
b.继续往下走定位到了具体的类 BeanFactoryCacheOperationSourceAdvisor,如下图4
在这里插入图片描述

c.后面的逻辑就是从advisors中获取配置的Interceptor,看到了BeanFactory相关我们一定要想到是应用启动的时候初始化的相关操作,于是我们应该想到第1步的启动类增加@EnableCaching这个注解,所以我们回到开始的位置往下跟踪。

d.我们发现@EnableCacheing 下面有一个 @Import({CachingConfigurationSelector.class}) 注解,我们跟进去到selectImports —>getProxyImports,在getProxyImports方法里面看到了下面的代码 图5
在这里插入图片描述

e.继续进入到ProxyCachingConfiguration 类,终于看到了BeanFactoryCacheOperationSourceAdvisor 是不是就和第4步关联起来了?是不是就和CacheInterceptor关联起来了?图6
在这里插入图片描述

5.具体方法的@Cacheable 注解是怎么和CacheInterceptor 关联起来的呢?

我们继续从图4往下走

# 第一步
定位到了 CacheOperationSourcePointcut.matches()方法
#第二步
AbstractFallbackCacheOperationSource.getCacheOperations()方法
#第三步 最终key 从 attributeCache 获取
public Collection<CacheOperation> getCacheOperations(Method method, @Nullable Class<?> targetClass) {
        ....省略非关键代码
        # 从缓存中获取key
        Object cacheKey = this.getCacheKey(method, targetClass);
          Collection<CacheOperation> cached = (Collection)this.attributeCache.get(cacheKey);
          if (cached != null) {
              return cached != NULL_CACHING_ATTRIBUTE ? cached : null;
          } else {
              # 如果缓存中没有key ,判断该方法是否存在CacheOperation操作
              Collection<CacheOperation> cacheOps = this.computeCacheOperations(method, targetClass);
              if (cacheOps != null) {
                  if (this.logger.isTraceEnabled()) {
                      this.logger.trace("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheOps);
                  }
                  # 存在CacheOperation操作,放入缓存
                  this.attributeCache.put(cacheKey, cacheOps);
              } else {
                  # 存在CacheOperation操作,存入空集合
                  this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
              }

              return cacheOps;
          }
    }

跟踪 this.computeCacheOperations()方法,定位到parseCacheAnnotations()方法,最终看到了Cacheable、CacheEvict、CachePut等相关注解,自此所有谜底就已经全部解开了。

# SpringCacheAnnotationParser.parseCacheAnnotations()方法
Collection<CacheOperation> ops = new ArrayList(1);
            anns.stream().filter((ann) -> {
                return ann instanceof Cacheable;
            }).forEach((ann) -> {
                ops.add(this.parseCacheableAnnotation(ae, cachingConfig, (Cacheable)ann));
            });
            anns.stream().filter((ann) -> {
                return ann instanceof CacheEvict;
            }).forEach((ann) -> {
                ops.add(this.parseEvictAnnotation(ae, cachingConfig, (CacheEvict)ann));
            });
            anns.stream().filter((ann) -> {
                return ann instanceof CachePut;
            }).forEach((ann) -> {
                ops.add(this.parsePutAnnotation(ae, cachingConfig, (CachePut)ann));
            });
            anns.stream().filter((ann) -> {
                return ann instanceof Caching;
            }).forEach((ann) -> {
                this.parseCachingAnnotation(ae, cachingConfig, (Caching)ann, ops);
            });
            return ops;

6. 总结

前面我们自下而上的从假设到验证的梳理了springboot下@Cachebale的实现原理,我们再自上而下的总结下大的步骤。
  a.EnableCaching 初始化advisor,注册interceptor拦截器

  b.容器初始化的时候把带有Cache相关注解的方法放入attributeCache中缓存起来

  c.带有Cache的方法通过Cglib动态代理增强织入拦截器

  d.结合a、b的初始化信息定位到CacheIntercepthor拦截器,实现缓存的增、删、改功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值