SpringBoot 缓存的原码分析

@EnableCache

理解Spring的缓存首先从 @EnableCache这个注解说起,这个注解是开启缓存功能的关键,通过源码分析可以知道 

@EnableCache 注解 通过 @Import引入 CachingConfigurationSelector ,其向相容其中注册两个Bean, AutoProxyRegistrar以及ProxyCachingConfiguration,下面分别介绍这两个Bean的用处

 

1> org.springframework.context.annotation.AutoProxyRegistrar 实现了ImportBeanDefinitonRegistar 接口 ,此接口又再次向容器中注册

 internalAutoProxyCreator = InfrastructureAdvisorAutoProxyCreator

 

2> org.springframework.cache.annotation.ProxyCachingConfiguration 是一个Bean定义文件 注册了以下3个实例到容器中

 org.springframework.cache.config.internal.CacheAdvisor

 org.springframework.cache.interceptor.CacheInterceptor

 org.springframework.cache.interceptor.CacheOperationSource

 

CacheOperationSource介绍

这个类主要 通过getCacheOperations 返回缓存操作(CacheOperation)的集合。我们这里关注他的一个实现类AnnotationCacheOperationSource作用是获取定义在类和方法上的SpringCache相关的标注并将其转换为对应的CacheOperation属性。 对SpringCache的几个标注@Cacheable、@CachePut、@CacheEvict、@Caching进行了解析,并相应的创建CacheableOperation、CacheEvictOperation、CachePutOperation   

AnnotationCacheOperationSource中还有一个CacheOperation的解析器 默认使用 SpringCacheAnnotationParser, 通过解析器将标注的注解解析成 CacheOperation 集合返回

 

CacheOperation介绍

缓存操作的基类,他的实现类有CacheableOperation、CacheEvictOperation、CachePutOperation

CacheableOperation: 顾名思义,就是执行缓存的put操作

CacheEvictOperation: 执行缓存的Evict 移除操作

CacheableOperation: 缓存的保存操作,和put是由区别的,put时候始终都会调用缓存的方法,而cachebale有缓存直接获取

 

CacheInterceptor介绍

通过源码查看可知CacheInterceptor 实现了 MethodInterceptor 是一个拦截器,类的继承关系如下:

CacheInterceptor 

    -> CacheAspectSupport implements BeanFactoryAware, InitializingBean, SmartInitializingSingleton

        -> AbstractCacheInvoker

 

cacheInterceptor中只有一个 invoke 方法,这个方法就是执行缓存相关操作的方法,里面通过invocation.proceed() 执行完整个拦截器链;

 

从上面可以看出CacheAspectSupport 实现 BeanFactoryAware接口 ,SmartInitializingSingleton接口 

 

 

 

InfrastructureAdvisorAutoProxyCreator介绍

InfrastructureAdvisorAutoProxyCreator是一个后置处理器,其继承关系如下:

InfrastructureAdvisorAutoProxyCreator

    ->AbstractAdvisorAutoProxyCreator

        ->AbstractAutoProxyCreator implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

            ->ProxyProcessorSupport

从以上可知 SmartInstantiationAwareBeanPostProcessor 是一个后置处理器,返回一个增强后代理对象,其主要是在Bean创建厨师换完成后调用 postProcessAfterInitialization 时返回一个增强代理对象(这点逻辑和AOP完全一样)

 

@Override

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {

   if (bean != null) {

      Object cacheKey = getCacheKey(bean.getClass(), beanName);

      if (!this.earlyProxyReferences.contains(cacheKey)) {

         return wrapIfNecessary(bean, beanName, cacheKey);

      }

   }

   return bean;

}

 

执行流程:

使用代理对象调用方法时,会被cglib拦截

1、 System.out.println(calculator.div(1,1)); 执行到这里跟踪进去

2、调用了CglibAopProxy.intercept方法

 

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

   Object oldProxy = null;

   boolean setProxyContext = false;

   Object target = null;

   TargetSource targetSource = this.advised.getTargetSource();

   try {

      if (this.advised.exposeProxy) {

         // Make invocation available if necessary.

         oldProxy = AopContext.setCurrentProxy(proxy);

         setProxyContext = true;

      }

      // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...

      target = targetSource.getTarget();

      Class<?> targetClass = (target != null ? target.getClass() : null);

      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      Object retVal;

      // Check whether we only have one InvokerInterceptor: that is,

      // no real advice, but just reflective invocation of the target.

      if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {

         // We can skip creating a MethodInvocation: just invoke the target directly.

         // Note that the final invoker must be an InvokerInterceptor, so we know

         // it does nothing but a reflective operation on the target, and no hot

         // swapping or fancy proxying.

         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);

         retVal = methodProxy.invoke(target, argsToUse);

      }

      else {

         // We need to create a method invocation...

         retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

      }

      retVal = processReturnType(proxy, target, method, retVal);

      return retVal;

   }

   finally {

      if (target != null && !targetSource.isStatic()) {

         targetSource.releaseTarget(target);

      }

      if (setProxyContext) {

         // Restore old proxy.

         AopContext.setCurrentProxy(oldProxy);

      }

   }

}

 

3> 最主要的是红色标注的 proceed方法 ,跟踪进去:ReflectiveMethodInvocation 的proceed方法:

@Override

@Nullable

public Object proceed() throws Throwable {

   // We start with an index of -1 and increment early.

   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {

      return invokeJoinpoint();

   }

 

   Object interceptorOrInterceptionAdvice =

         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

      // Evaluate dynamic method matcher here: static part will already have

      // been evaluated and found to match.

      InterceptorAndDynamicMethodMatcher dm =

            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;

      if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {

         return dm.interceptor.invoke(this);

      }

      else {

         // Dynamic matching failed.

         // Skip this interceptor and invoke the next in the chain.

         return proceed();

      }

   }

   else {

      // It's an interceptor, so we just invoke it: The pointcut will have

      // been evaluated statically before this object was constructed.

      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

   }

}

 

4> 跟踪进去发现调用的 CacheInterceptor的invoke方法,里面调用了父类的execute方法也就是 CacheAspectSupport的 execute方法

@Nullable

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 cacheOperationSource = getCacheOperationSource();

      if (cacheOperationSource != null) {

         Collection<CacheOperation> operations = cacheOperationSource.getCacheOperations(method, targetClass);

         if (!CollectionUtils.isEmpty(operations)) {

            return execute(invoker, method,

                  new CacheOperationContexts(operations, method, args, target, targetClass));

         }

      }

   }

 

   return invoker.invoke();

}

 

通过 Collection<CacheOperation> operations = cacheOperationSource.getCacheOperations(method, targetClass); 获取到 cacheableOperation; 然后再执行 CacheAspectSupport的另外一个重载方法 execute(invoker, method,

                  new CacheOperationContexts(operations, method, args, target, targetClass));

 

5> CacheAspectSupport的另外一个重载方法execute

@Nullable

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, () -> 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);

      }

   }

 

 

   // 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<>();

   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);

 

   return returnValue;

}

 

   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值