zoukankan      html  css  js  c++  java
  • Spring Cache 带你飞(一)

    Spring 3.1 版本引入基于 annotation 的 cache 技术,提供了一套抽象的缓存实现方案,通过注解方式使用缓存,基于配置的方式灵活使用不同缓存组件。代码具有相当的灵活性和扩展性,本文基于 Spring 5.x 源码一起分析 Spring Cache 的代码艺术。

    开启 Spring Cache

    想让 Spring 提供 Cache 能力很简单,只需要在启动类加上 @EnableCaching 注解即可:

    @Configuration
    @EnableCaching
    public class ServerMain {
    
    }
    

    通过在启动类上添加 EnableCaching 注解将 Cache 相关的组件注入到 Spring 启动中,通过 Proxy 或者 AspectJ 的方式获取 Cache 对应的执行信息。

    如果你希望在启动时修改一些 Cache 底层对应的基础管理信息,可以通过在启动类上覆盖 CachingConfigurerSupport 提供的相关方法来实现:

    @EnableCaching
    @SpringBootApplication
    public class WebDemoApplication extends CachingConfigurerSupport {
    
        public static void main(String[] args) {
            SpringApplication.run(WebDemoApplication.class, args);
        }
    
    
        @Override
        public CacheManager cacheManager() {
            return super.cacheManager();
        }
    
        @Override
        public KeyGenerator keyGenerator() {
            return super.keyGenerator();
        }
    }
    

    上面的示例代码中重写了 CacheManager 和 KeyGenerator 两个类的构建实现,分别实现的功能是 Cache 管理方式和 Cache key 生成方式。

    从 Bean 加载机制了解 Spring 的 Cache 执行管理

    从启动类入手我们很容易看到整体的 Cache 管理方式:

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import({CachingConfigurationSelector.class})
    public @interface EnableCaching {
        boolean proxyTargetClass() default false;
    
        AdviceMode mode() default AdviceMode.PROXY;
    
        int order() default 2147483647;
    }
    
    • proxyTargetClass:false,表示使用 JDK 代理,true 表示使用 cglib 代理。

    • mode:指定 AOP 的模式,当值为 AdviceMode.PROXY 时表示使用 Spring aop,当值为当值为AdviceMode.ASPECTJ 时,表示使用 AspectJ。

    EnableCaching 使用时导入 CachingConfigurationSelector 类,我们看看加载了什么信息:

    public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
    
        public String[] selectImports(AdviceMode adviceMode) {
            switch(adviceMode) {
                case PROXY:
                    return this.getProxyImports();
                case ASPECTJ:
                    return this.getAspectJImports();
                default:
                    return null;
            }
        }
        ......
        ......
        ......
    
        static {
            ClassLoader classLoader = CachingConfigurationSelector.class.getClassLoader();
            jsr107Present = ClassUtils.isPresent("javax.cache.Cache", classLoader);
            jcacheImplPresent = ClassUtils.isPresent("org.springframework.cache.jcache.config.ProxyJCacheConfiguration", classLoader);
        }
    
    
    }
    

    可以看到主要做了一件事,通过代理方式的不同加载对应的 CacheConfiguration :

    • 如果是 JDK Proxy,加载 AutoProxyRegistrar 类和 ProxyCachingConfiguration 类;
    • 如果是 AspectJ,则加载 AspectJCachingConfiguration 类。

    Spring Boot 默认使用 JDK Proxy,我们就看 JDK Proxy 的使用。

    AutoProxyRegistrar 的作用就是创建代理对象,内部通过调用 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry) 方法在 IOC 容器中注册一个 AutoProxyCreator。最终注入到容器中的 AutoProxyRegistrar 是一个 InfrastructureAdvisorAutoProxyCreator 类型:

    @Nullable
    public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
        return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
    }
    

    InfrastructureAdvisorAutoProxyCreator 类型只会为基础设施类型的 Advisor 自动创建代理对象。它只会去找符合条件的 bean创建代理,从源码可见只有 role 为 BeanDefinition.ROLE_INFRASTRUCTURE 的满足条件。

    ProxyCachingConfiguration 创建了 3 个 bean,CacheOperationSource 关注如何获取所有拦截的切面,

    CacheInterceptor 解决要对拦截到的切面做什么。

    public class ProxyCachingConfiguration extends AbstractCachingConfiguration {
       
        @Bean(
            name = {"org.springframework.cache.config.internalCacheAdvisor"}
        )
        @Role(2)
        public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor(CacheOperationSource cacheOperationSource, CacheInterceptor cacheInterceptor) {
            BeanFactoryCacheOperationSourceAdvisor advisor = new BeanFactoryCacheOperationSourceAdvisor();
            advisor.setCacheOperationSource(cacheOperationSource);
            advisor.setAdvice(cacheInterceptor);
            if (this.enableCaching != null) {
                advisor.setOrder((Integer)this.enableCaching.getNumber("order"));
            }
    
            return advisor;
        }
        ......
    }
    

    BeanFactoryCacheOperationSourceAdvisor 是 Spring Cache 自己实现的 Advisor,会对所有能取出 CacheOperation 的方法执行 CacheInterceptor 这个 Advice。

    小知识:

    Spring AOP 的创建过程本质是实现一个 BeanPostProcessor,在创建 bean 的过程中创建 Proxy,并且为 Proxy 绑定所有适用于该 bean 的 advisor,最终暴露给容器。

    Spring 中 AOP 几个关键的概念 advisor, advice, pointcut

    advice = 切面拦截中插入的行为

    pointcut = 切面的切入点

    advisor = advice + pointcut

    BeanFactoryCacheOperationSourceAdvisor内部的切入点实现类是 CacheOperationSourcePointcut,切入的逻辑如下:

    abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
    	
        private class CacheOperationSourceClassFilter implements ClassFilter {
            private CacheOperationSourceClassFilter() {
            }
    
            public boolean matches(Class<?> clazz) {
                if (CacheManager.class.isAssignableFrom(clazz)) {
                    return false;
                } else {
                    CacheOperationSource cas = CacheOperationSourcePointcut.this.getCacheOperationSource();
                    return cas == null || cas.isCandidateClass(clazz);
                }
            }
        }
    }
    

    可以看到切入点主要就是判断被切入的方法上是否有注解:CacheOperationSourcePointcut.this.getCacheOperationSource()

    ProxyCachingConfiguration 中还有另一个值得关注的类 - AnnotationCacheOperationSource

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public CacheOperationSource cacheOperationSource() {
        return new AnnotationCacheOperationSource();
    }
    

    CacheOperationSource 持有一个 CacheAnnotationParser 列表。 CacheAnnotationParser 只有一个实现类:SpringCacheAnnotationParser

    public class SpringCacheAnnotationParser implements CacheAnnotationParser, Serializable {
    
        private static final Set<Class<? extends Annotation>> CACHE_OPERATION_ANNOTATIONS = new LinkedHashSet<>(8);
    
        static {
            CACHE_OPERATION_ANNOTATIONS.add(Cacheable.class);
            CACHE_OPERATION_ANNOTATIONS.add(CacheEvict.class);
            CACHE_OPERATION_ANNOTATIONS.add(CachePut.class);
            CACHE_OPERATION_ANNOTATIONS.add(Caching.class);
        }
        ......
        @Nullable
    	private Collection<CacheOperation> parseCacheAnnotations(
    			DefaultCacheConfig cachingConfig, AnnotatedElement ae, boolean localOnly) {
    
    		Collection<? extends Annotation> anns = (localOnly ?
    				AnnotatedElementUtils.getAllMergedAnnotations(ae, CACHE_OPERATION_ANNOTATIONS) :
    				AnnotatedElementUtils.findAllMergedAnnotations(ae, CACHE_OPERATION_ANNOTATIONS));
    		if (anns.isEmpty()) {
    			return null;
    		}
    
    		final Collection<CacheOperation> ops = new ArrayList<>(1);
    		anns.stream().filter(ann -> ann instanceof Cacheable).forEach(
    				ann -> ops.add(parseCacheableAnnotation(ae, cachingConfig, (Cacheable) ann)));
    		anns.stream().filter(ann -> ann instanceof CacheEvict).forEach(
    				ann -> ops.add(parseEvictAnnotation(ae, cachingConfig, (CacheEvict) ann)));
    		anns.stream().filter(ann -> ann instanceof CachePut).forEach(
    				ann -> ops.add(parsePutAnnotation(ae, cachingConfig, (CachePut) ann)));
    		anns.stream().filter(ann -> ann instanceof Caching).forEach(
    				ann -> parseCachingAnnotation(ae, cachingConfig, (Caching) ann, ops));
    		return ops;
    	}
        ......
    }
    

    可以看到 Parser 的作用就是将注解对应的方法解析成 CacheOperation 存起来。

    看到这里我们开始有点眉目,开始知道去哪里找拦截了什么和操作了什么。接下来继续对 CacheOperationCacheInterceptor 进行深入。

    CacheOperation

    CacheOperationSource 接口中只有一个方法:

    public interface CacheOperationSource {
        default boolean isCandidateClass(Class<?> targetClass) {
            return true;
        }
    
        @Nullable
        Collection<CacheOperation> getCacheOperations(Method method, @Nullable Class<?> targetClass);
    }
    

    该接口中只有一个方法:通过接口和类名获得对应的 CacheOperationCacheOperation 是对缓存操作的抽象封装,它的实现类有 3 个:

    三个实现类分别对应着 @CacheEvict@CachePut@Cacheable 注解。

    CacheInterceptor

    CacheInterceptor 实现的功能就是对 目标方法的实际拦截操作:

    public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {
    
        @Override
        @Nullable
        public Object invoke(final MethodInvocation invocation) throws Throwable {
            Method method = invocation.getMethod();
    
            CacheOperationInvoker aopAllianceInvoker = () -> {
                try {
                    return invocation.proceed();
                }
                catch (Throwable ex) {
                    throw new CacheOperationInvoker.ThrowableWrapper(ex);
                }
            };
    
            Object target = invocation.getThis();
            Assert.state(target != null, "Target must not be null");
            try {
                return execute(aopAllianceInvoker, target, method, invocation.getArguments());
            }
            catch (CacheOperationInvoker.ThrowableWrapper th) {
                throw th.getOriginal();
            }
        }
    
    }
    

    CacheInterceptor 代码很简洁,采用函数的形式封装了真正要执行的函数逻辑,最终把此函数传交给父类的 execute()去执行。很显然最终执行目标方法的是 invocation.proceed()。我们直接去父类 CacheAspectSupport 看相关代码逻辑:

    public abstract class CacheAspectSupport extends AbstractCacheInvoker
    		implements BeanFactoryAware, InitializingBean, SmartInitializingSingleton {
    
    	protected final Log logger = LogFactory.getLog(getClass());
    
    	private final Map<CacheOperationCacheKey, CacheOperationMetadata> metadataCache = new ConcurrentHashMap<>(1024);
    
    	private final CacheOperationExpressionEvaluator evaluator = new CacheOperationExpressionEvaluator();
    
    	@Nullable
    	private CacheOperationSource cacheOperationSource;
    
    	private SingletonSupplier<KeyGenerator> keyGenerator = SingletonSupplier.of(SimpleKeyGenerator::new);
    
    	@Nullable
    	private SingletonSupplier<CacheResolver> cacheResolver;
    	
        ......
    }
    

    上面摘录出 的一些属性:

    Map<CacheOperationCacheKey, CacheOperationMetadata> metadataCache

    这个 Map 缓存了所有被注解修饰的类或者方法对应的基本属性信息。

    CacheOperationExpressionEvaluator evaluator

    解析一些 condition、key、unless 等可以写 el 表达式的处理器。

    SingletonSupplier<KeyGenerator> keyGenerator

    key 生成器默认使用的 SimpleKeyGenerator,注意 SingletonSupplier 是 Spring5.1 的新类,实现了接口java.util.function.Supplier ,主要是对 null 值进行容错。

    接着看相关的方法:

    public abstract class CacheAspectSupport extends AbstractCacheInvoker
    		implements BeanFactoryAware, InitializingBean, SmartInitializingSingleton {
        
        
        // 这个接口来自于 SmartInitializingSingleton  在实例化完所有单例Bean后调用
        //可以看到在这里实例化 CacheManager, CacheManager 我们后面会说作用
     	@Override
    	public void afterSingletonsInstantiated() {
    		if (getCacheResolver() == null) {
    			// Lazily initialize cache resolver via default cache manager...
    			Assert.state(this.beanFactory != null, "CacheResolver or BeanFactory must be set on cache aspect");
    			try {
    				setCacheManager(this.beanFactory.getBean(CacheManager.class));
    			}
    			catch (NoUniqueBeanDefinitionException ex) {
    				throw new IllegalStateException("No CacheResolver specified, and no unique bean of type " +
    						"CacheManager found. Mark one as primary or declare a specific CacheManager to use.", ex);
    			}
    			catch (NoSuchBeanDefinitionException ex) {
    				throw new IllegalStateException("No CacheResolver specified, and no bean of type CacheManager found. " +
    						"Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.", ex);
    			}
    		}
    		this.initialized = true;
    	}   
        
       
        //根据CacheOperation 封装CacheOperationMetadata
        protected CacheOperationMetadata getCacheOperationMetadata(
    			CacheOperation operation, Method method, Class<?> targetClass) {
    
    		CacheOperationCacheKey cacheKey = new CacheOperationCacheKey(operation, method, targetClass);
    		CacheOperationMetadata metadata = this.metadataCache.get(cacheKey);
    		if (metadata == null) {
    			KeyGenerator operationKeyGenerator;
    			if (StringUtils.hasText(operation.getKeyGenerator())) {
    				operationKeyGenerator = getBean(operation.getKeyGenerator(), KeyGenerator.class);
    			}
    			else {
    				operationKeyGenerator = getKeyGenerator();
    			}
    			CacheResolver operationCacheResolver;
    			if (StringUtils.hasText(operation.getCacheResolver())) {
    				operationCacheResolver = getBean(operation.getCacheResolver(), CacheResolver.class);
    			}
    			else if (StringUtils.hasText(operation.getCacheManager())) {
    				CacheManager cacheManager = getBean(operation.getCacheManager(), CacheManager.class);
    				operationCacheResolver = new SimpleCacheResolver(cacheManager);
    			}
    			else {
    				operationCacheResolver = getCacheResolver();
    				Assert.state(operationCacheResolver != null, "No CacheResolver/CacheManager set");
    			}
    			metadata = new CacheOperationMetadata(operation, method, targetClass,
    					operationKeyGenerator, operationCacheResolver);
    			this.metadataCache.put(cacheKey, metadata);
    		}
    		return metadata;
    	}
        
        
        
        
        //真正执行目标方法+ 缓存 的实现
    	@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)
            // 如果已经初始化过(有CacheManager,CacheResolver),执行这里
    		if (this.initialized) {
                //getTargetClass拿到原始Class  解剖代理
    			Class<?> targetClass = getTargetClass(target);
                //简单的说就是拿到该方法上所有的CacheOperation缓存操作,最终一个一个的执行
    			CacheOperationSource cacheOperationSource = getCacheOperationSource();
    			if (cacheOperationSource != null) {
                    // CacheOperationContexts是非常重要的一个私有内部类
    				// 注意它是复数!不是CacheOperationContext单数  
                    // 所以它就像持有多个注解上下文一样  一个个执行
    				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();
    	}
    
        
        
        
        //内部调用的 execute 方法 
    	@Nullable
    	private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
    		// 判断是否同步执行
    		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, handleSynchronizedGet(invoker, key, cache));
    				}
    				catch (Cache.ValueRetrievalException ex) {
    					// Directly propagate ThrowableWrapper from the invoker,
    					// or potentially also an IllegalArgumentException etc.
    					ReflectionUtils.rethrowRuntimeException(ex.getCause());
    				}
    			}
    			else {
    				// No caching required, only call the underlying method
    				return invokeOperation(invoker);
    			}
    		}
    
    
    		
    		// sync=false的情况,走这里
    
    		
    		// Process any early evictions  beforeInvocation=true的会在此处最先执行~~~
    		
    		// 最先处理@CacheEvict注解~~~真正执行的方法请参见:performCacheEvict
    		// context.getCaches()拿出所有的caches,看看是执行cache.evict(key);方法还是cache.clear();
    		// 需要注意的的是context.isConditionPassing(result); condition条件此处生效,并且可以使用#result
    		// context.generateKey(result)也能使用#result
    		// @CacheEvict没有unless属性
    		processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
    				CacheOperationExpressionEvaluator.NO_RESULT);
    
    		// 执行@Cacheable  看看缓存是否能够命中
    		Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
    
    		// 如果缓存没有命中,那就准备一个cachePutRequest
    		// 因为@Cacheable首次进来肯定命中不了,最终肯定是需要执行一次put操作,这样下次进来就能命中
    		List<CachePutRequest> cachePutRequests = new ArrayList<>();
    		if (cacheHit == null) {
    			collectPutRequests(contexts.get(CacheableOperation.class),
    					CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
    		}
    
    		Object cacheValue;
    		Object returnValue;
    		// 如果缓存命中了,并且并且没有@CachePut的话,也就直接返回
    		if (cacheHit != null && !hasCachePut(contexts)) {
    			cacheValue = cacheHit.get();
    			returnValue = wrapCacheValue(method, cacheValue);
    		}
    		else {
    			// 有 cachePut 的情况,先执行目标方法再 put 缓存
    			returnValue = invokeOperation(invoker);
    			cacheValue = unwrapReturnValue(returnValue);
    		}
    
    		// 封装cacheput对象
    		collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);
    
    		// 真正统一执行 cacheput 的地方
    		for (CachePutRequest cachePutRequest : cachePutRequests) {
    			cachePutRequest.apply(cacheValue);
    		}
    
    		// 最后才执行 cacheEvict
    		processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);
    
    		return returnValue;
    	}
        
        
        
       
    	//缓存属性上下文对象
    	private class CacheOperationContexts {
    
    		private final MultiValueMap<Class<? extends CacheOperation>, CacheOperationContext> contexts;
    		//检查注解是否配置同步执行的开关
    		private final boolean sync;
    
    		public CacheOperationContexts(Collection<? extends CacheOperation> operations, Method method,
    				Object[] args, Object target, Class<?> targetClass) {
    			
                //将当前 method 上所有缓存操作封装到一个map 对象中
    			this.contexts = new LinkedMultiValueMap<>(operations.size());
    			for (CacheOperation op : operations) {
    				this.contexts.add(op.getClass(), getOperationContext(op, method, args, target, targetClass));
    			}
                //同步执行与否取决于这个函数
    			this.sync = determineSyncFlag(method);
    		}
    
    		public Collection<CacheOperationContext> get(Class<? extends CacheOperation> operationClass) {
    			Collection<CacheOperationContext> result = this.contexts.get(operationClass);
    			return (result != null ? result : Collections.emptyList());
    		}
    
    		public boolean isSynchronized() {
    			return this.sync;
    		}
    
            //只有@Cacheable有sync属性,所以只需要看CacheableOperation即可
    		private boolean determineSyncFlag(Method method) {
    			List<CacheOperationContext> cacheOperationContexts = this.contexts.get(CacheableOperation.class);
    			if (cacheOperationContexts == null) {  // no @Cacheable operation at all
    				return false;
    			}
    			boolean syncEnabled = false;
                //只要有一个@Cacheable的sync=true了,那就为true  并且下面还有检查逻辑
    			for (CacheOperationContext cacheOperationContext : cacheOperationContexts) {
    				if (((CacheableOperation) cacheOperationContext.getOperation()).isSync()) {
    					syncEnabled = true;
    					break;
    				}
    			}
                // 执行sync=true的检查逻辑
    			if (syncEnabled) {
                    // sync=true时候,不能还有其它的缓存操作 也就是说@Cacheable(sync=true)的时候只能单独使用
    				if (this.contexts.size() > 1) {
    					throw new IllegalStateException(
    							"@Cacheable(sync=true) cannot be combined with other cache operations on '" + method + "'");
    				}
                    //@Cacheable(sync=true)时,多个@Cacheable也是不允许的
    				if (cacheOperationContexts.size() > 1) {
    					throw new IllegalStateException(
    							"Only one @Cacheable(sync=true) entry is allowed on '" + method + "'");
    				}
                    // 拿到唯一的一个@Cacheable
    				CacheOperationContext cacheOperationContext = cacheOperationContexts.iterator().next();
    				CacheableOperation operation = (CacheableOperation) cacheOperationContext.getOperation();
                    //@Cacheable(sync=true)时,cacheName只能使用一个
    				if (cacheOperationContext.getCaches().size() > 1) {
    					throw new IllegalStateException(
    							"@Cacheable(sync=true) only allows a single cache on '" + operation + "'");
    				}
                    //sync=true时,unless属性是不支持的,并且是不能写的
    				if (StringUtils.hasText(operation.getUnless())) {
    					throw new IllegalStateException(
    							"@Cacheable(sync=true) does not support unless attribute on '" + operation + "'");
    				}
    				return true;
    			}
    			return false;
    		}
    	}
    
        
    }
    

    execute 相关的代码上面注解写的很清晰,大家可以跟着多看几遍。这里还有一点没有说,最终的 get Cache 或者 put Cache 的操作在哪里呢?刚才在 execute 方法中有一句代码:

    Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
    

    这里我们看到是先查缓存中是否有该 Cache,进去看有个 findCaches 方法:

    @Nullable
    private Cache.ValueWrapper findInCaches(CacheOperationContext context, Object key) {
        for (Cache cache : context.getCaches()) {
            Cache.ValueWrapper wrapper = doGet(cache, key);
            if (wrapper != null) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Cache entry for key '" + key + "' found in cache '" + cache.getName() + "'");
                }
                return wrapper;
            }
        }
        return null;
    }
    

    重点关注 doGet 方法,可以看到这个方法是父类 AbstractCacheInvoker 中的,同类里面还有 doPut,doEvict 和 doClear。

    小知识

    @Cacheable 注解 sync=true 的效果

    多线程环境下存在多个操作使用相同的参数同步调用相同的 key,默认情况下缓存不锁定任何资源所以可能导致多次计算。对于这种情况,sync 属性可以将底层锁住,使得只有一个线程进行操作,其他线程堵塞直到更新完缓存返回结果。

    小结

    至此我们把上面说过的内容总结一下:

    BeanFactoryCacheOperationSourceAdvisor

    配置 Cache 的切面和拦截实现。拦截的对象即解析出来的 CacheOperation 对象。

    每一个 CacheOperation 在执行的时候被封装为 CacheOperationContext 对象(一个方法可能被多个注解修饰),最终通过 CacheResolver 解析出缓存对象 Cache。

    CacheOperation

    封装了@CachePut@Cacheable@CacheEvict的属性信息,以便于拦截的时候能直接操作此对象来执行逻辑。

    解析注解对应的代码为 CacheOperation 的工作是 CacheAnnotationParser 来完成的。

    CacheInterceptor

    CacheInterceptor 执行真正的方法执行和 Cache 操作。最终调用其父类提供的四个 do 方法处理 Cache。

    以上整体过程为 Spring 启动对相关注解所在类或者方法的拦截和注入,从而实现 Cache 逻辑。限于篇幅本篇暂讨论这些内容,下一篇我们来看 Spring 如何实现对多缓存底层方案的支持(本地 Cache,Redis,Guava Cache,Caffeine Cache)。

  • 相关阅读:
    ole辅助类sqlhelperaccess
    Asp.net中常用的26个性能优化方法
    MVP模式的相关知识
    ASP.NET AJAX入门系列
    非常实用]Asp.net常用的51个代码
    一步一步学Silverlight 系列文章
    .NET设计模式系列文章
    Asp.net添加上传进度条
    asp.net 用ajax实现文件上传
    增加弹出层的拖拽功能
  • 原文地址:https://www.cnblogs.com/rickiyang/p/15495394.html
Copyright © 2011-2022 走看看