spring缓存源码解析


大家都知道spring的缓存机制,可能都会用缓存标签@Cacheable等标签,可是大家有没有想过,为什么在方法上加了标签以后,这个方法就能用缓存呢,作为一名咸鱼coding,当然要知其然也要知其所以然啦,废话不多说,开始吧!

首先我们应该意识到,@Cache运用的是java的动态代理技术,java会给运用了缓存的标签生成一个动态的代理类,如果实现了接口,运用的就是jdk的动态代理,类的动态代理用的是cglib的动态代理技术,那么动态代理类是什么时候生成的呢,首先是spring默认的配置一个advisor(要理解advisor大家首先要知道springAOP的知识):

@Configuration
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {

   @Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor() {
      BeanFactoryCacheOperationSourceAdvisor advisor =
            new BeanFactoryCacheOperationSourceAdvisor();
      advisor.setCacheOperationSource(cacheOperationSource());
      advisor.setAdvice(cacheInterceptor());
      if (this.enableCaching != null) {
         advisor.setOrder(this.enableCaching.<Integer>getNumber("order"));
      }
      return advisor;
   }
 //这是为了后面的切点执行时候需要的,为什么这么说后面我会说明;
   @Bean
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public CacheOperationSource cacheOperationSource() {
      return new AnnotationCacheOperationSource();
   }

//我的理解这是一个增强
   @Bean
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public CacheInterceptor cacheInterceptor() {
      CacheInterceptor interceptor = new CacheInterceptor();
      interceptor.setCacheOperationSources(cacheOperationSource());
      if (this.cacheResolver != null) {
         interceptor.setCacheResolver(this.cacheResolver);
      }
      else if (this.cacheManager != null) {
         interceptor.setCacheManager(this.cacheManager);
      }
      if (this.keyGenerator != null) {
         interceptor.setKeyGenerator(this.keyGenerator);
      }
      if (this.errorHandler != null) {
         interceptor.setErrorHandler(this.errorHandler);
      }
      return interceptor;
   }

}

我们再来看看BeanFactoryCacheOperationSourceAdvisor,
public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

   @Nullable
   private CacheOperationSource cacheOperationSource;

 //CacheOperationSourcePointcut相当于一个切点,运用了CacheOperationSource的判断逻辑

 private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
      @Override
      @Nullable
      protected CacheOperationSource getCacheOperationSource() {
         return cacheOperationSource;
      }
   };


   /**
    * Set the cache operation attribute source which is used to find cache
    * attributes. This should usually be identical to the source reference
    * set on the cache interceptor itself.
    */
   public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {
      this.cacheOperationSource = cacheOperationSource;
   }

   /**
    * Set the {
  @link ClassFilter} to use for this pointcut.
    * Default is {
  @link ClassFilter#TRUE}.
    */
   public void setClassFilter(ClassFilter classFilter) {
      this.pointcut.setClassFilter(classFilter);
   }

   @Override
   public Pointcut getPointcut() {
      return this.pointcut;
   }

}

切面生成了,什么时候执行呢,spring默认的生成代理类的时候规则是这样的,先找到所有的class文件,然后去匹配所有的advisor,如果匹配成功,那么就生成代理类,执行的时候就植入通知(有的叫增强),我们不必知道具体的底层开始类(实际我也没有深究),我们只要知道当匹配advisor的时候会调用CacheOperationSourcePointcut的matches方法,matches方法的匹配逻辑是这样的,查找targetClass类上面是否有四个注解,分别是CacheableCacheEvictCachePut、Caching,如果有这四个注解,则生成TargetClass代理对象,并将注解信息缓存起来,具体的执行代码如下,大家也可以一直跟下去;

@SuppressWarnings("serial")
public class SpringCacheAnnotationParser implements CacheAnnotationParser, Serializable {

   @Override
   @Nullable
   public Collection<CacheOperation> parseCacheAnnotations(Class<?> type) {
      DefaultCacheConfig defaultConfig = getDefaultCacheConfig(type);
      return parseCacheAnnotations(defaultConfig, type);
   }

   @Override
   @Nullable
   public Collection<CacheOperation> parseCacheAnnotations(Method method) {
      DefaultCacheConfig defaultConfig = getDefaultCacheConfig(method.getDeclaringClass());
      return parseCacheAnnotations(defaultConfig, method);
   }

   @Nullable
   protected Collection<CacheOperation> parseCacheAnnotations(DefaultCacheConfig cachingConfig, AnnotatedElement ae) {
      Collection<CacheOperation> ops = parseCacheAnnotations(cachingConfig, ae, false);
      if (ops != null && ops.size() > 1 && ae.getAnnotations().length > 0) {
         // More than one operation found -> local declarations override interface-declared ones...
         Collection<CacheOperation> localOps = parseCacheAnnotations(cachingConfig, ae, true);
         if (localOps != null) {
            return localOps;
         }
      }
      return ops;
   }

   @Nullable
   private Collection<CacheOperation> parseCacheAnnotations(
         DefaultCacheConfig cachingConfig, AnnotatedElement ae, boolean localOnly) {

      Collection<CacheOperation> ops = null;

      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));
         }
      }
      Collection<CacheEvict> evicts = (localOnly ? AnnotatedElementUtils.getAllMergedAnnotations(ae, CacheEvict.cl
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Spring AOP是Spring框架中的一个重要模块,它提供了一种面向切面编程的方式,可以让开发者将一些通用的、横切的关注点(如事务、安全、缓存等)从业务逻辑中剥离出来,使得业务逻辑更加清晰简洁,代码复用更加方便。 Spring AOP的实现原理主要基于Java动态代理和CGLIB动态代理两种方式,其中Java动态代理主要用于接口代理,而CGLIB动态代理则主要用于类代理。Spring AOP中的核心概念是切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)和织入(Weaving)。 在Spring AOP中,切面是一个横向的关注点,它跨越多个对象和方法,通常包含一些通用的功能,如日志记录、安全控制等。连接点则是程序中可以被切面拦截的特定点,如方法调用、异常抛出等。通知是切面在连接点执行前后所执行的动作,包括前置通知(Before)、后置通知(After)、异常通知(AfterThrowing)、返回通知(AfterReturning)和环绕通知(Around)。切点则是用来匹配连接点的规则,它可以指定哪些连接点会被切面拦截。织入则是将切面应用到目标对象中的过程,它可以在编译时、类加载时、运行时等不同的阶段进行。 Spring AOP的源码解析涉及到很多细节,包括代理的生成、通知的执行、切点的匹配等,需要深入了解Spring框架的内部实现和Java的反射机制。对于初学者而言,可以先从Spring AOP的基本概念和用法入手,了解其实现原理的同时,也可以通过调试和查看源码来加深理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值