SpringCache源码分析,你学会了吗?

ProxyCachingConfiguration总的来说就是声明了一个SpringCacheAnn
首页 新闻资讯 行业资讯 SpringCache源码分析,你学会了吗?

1、入口说明

@EnableCaching是开启SpringCache的一个总开关,开启时候我们的缓存相关注解才会生效,所以我们@EnableCaching开始作为入口进行分析,

2、分析@EnableCaching注解

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(CachingConfigurationSelector.class)// 这里有一个Import,导入了一个Selector类public@interfaceEnableCaching {// 是否创建cglib代理,默认为false, 也就是使用jdk动态代理booleanproxyTargetClass()defaultfalse;// 增强模式 默认使用JDK动态代理,引入cglib可以使用ASPECTJAdviceModemode()defaultAdviceMode.PROXY;// 排序字段intorder()defaultOrdered.LOWEST_PRECEDENCE;}

2.1、分析导入的CachingConfigurationSelector类

publicclass CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching>{// ...此处省略一万行代码// CachingConfigurationSelector继承了AdviceModeImportSelector, 而AdviceModeImportSelector又实现了ImportSelector// 所以我们实现类selectImports,用于返回要导入的配置类列表@OverridepublicString[]selectImports(AdviceMode adviceMode){// 如果是jdk动态代理,走getProxyImports逻辑。如果是cglib动态代理,走getAspectJImports逻辑switch(adviceMode){casePROXY:returngetProxyImports();caseASPECTJ:returngetAspectJImports();default:returnnull;}
    }// 获取要进行自动配置的配置类private String[]getProxyImports(){
        List<String>result=new ArrayList<>(3);// 这里添加了两个类,AutoProxyRegistrar(自动代理注册器),ProxyCachingConfiguration(代理缓存配置类)// AutoProxyRegistrar点进去可以发现,里面其实就是提供了registerBeanDefinitions方法用于注册BeanDefinitionresult.add(AutoProxyRegistrar.class.getName());// ProxyCachingConfiguration点进去发现,配置类缓存相关的一些Bean(就是SpringCache的一些核心Bean)result.add(ProxyCachingConfiguration.class.getName());if(jsr107Present&&jcacheImplPresent){
            result.add(PROXY_JCACHE_CONFIGURATION_CLASS);}returnStringUtils.toStringArray(result);}// ...此处省略一万行代码}

CachingConfigurationSelector继承了AdviceModeImportSelector, 而AdviceModeImportSelector又实现了ImportSelector,所以我们实现了selectImports方法,用于返回要导入的配置类列表.

selectImports会去判断,如果是jdk动态代理,走getProxyImports逻辑。如果是cglib动态代理,走getAspectJImports逻辑。

我们直接关注JDK动态代理的方法getProxyImports。这里面添加了两个类AutoProxyRegistrar和ProxyCachingConfiguration。

AutoProxyRegistrar点进去可以发现,里面其实就是提供了registerBeanDefinitions方法用于注册BeanDefinition。

ProxyCachingConfiguration点进去发现,配置类缓存相关的一些Bean(就是SpringCache的一些核心Bean),所以我们会重点关注ProxyCachingConfiguration并着重分析。

2.1.1、分析ProxyCachingConfiguration配置类

@Configuration(proxyBeanMethods=false)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)publicclass ProxyCachingConfiguration extends AbstractCachingConfiguration {// BeanFactoryCacheOperationSourceAdvisor是对CacheOperationSource进行增强,其实就是添加一个拦截器,用于获取相关缓存的注解信息// 所以有些逻辑会在CacheInterceptor里@Bean(name=CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)publicBeanFactoryCacheOperationSourceAdvisor cacheAdvisor(CacheOperationSource cacheOperationSource,CacheInterceptor cacheInterceptor){

        BeanFactoryCacheOperationSourceAdvisor advisor=new BeanFactoryCacheOperationSourceAdvisor();advisor.setCacheOperationSource(cacheOperationSource);advisor.setAdvice(cacheInterceptor);if(this.enableCaching!=null){
            advisor.setOrder(this.enableCaching.<Integer>getNumber("order"));}returnadvisor;}// 定义一个CacheOperationSource,主要用于获取类或者方法上的注解。@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)publicCacheOperationSource cacheOperationSource(){returnnew AnnotationCacheOperationSource();}// 定义了一个拦截器,该拦截器用于用于拦截缓存相关注解,做AOP操作。比如先查询缓存,查询到直接返回,查询不到就执行方法体,将结果写入缓存。@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)publicCacheInterceptor cacheInterceptor(CacheOperationSource cacheOperationSource){
        CacheInterceptor interceptor=new CacheInterceptor();// 缓存拦截器在这里注入了cacheManager(缓存管理器)interceptor.configure(this.errorHandler,this.keyGenerator,this.cacheResolver,this.cacheManager);interceptor.setCacheOperationSource(cacheOperationSource);returninterceptor;}

}

来分析一下BeanFactoryCacheOperationSourceAdvisor

public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
    @Nullable
    private CacheOperationSource cacheOperationSource;

    // 定义我们自己的切点,缓存操作切点
    private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
        // 该切点存在一个方法,获取CacheOperationSource(获取切点的那些注解操作)。
        @Override
        @Nullable
        protected CacheOperationSource getCacheOperationSource() {
            return cacheOperationSource;
        }
    };
    
    // 使用该方法设置CacheOperationSource,在上一层有设置advisor.setCacheOperationSource(cacheOperationSource);
    // 把这个数据塞入BeanFactoryCacheOperationSourceAdvisor, 以便于在自定义的切点类CacheOperationSourcePointcut中可以获取
    public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {
        this.cacheOperationSource = cacheOperationSource;
    }
    
    // 设置ClassFilter到CacheOperationSourcePointcut
    public void setClassFilter(ClassFilter classFilter) {
        this.pointcut.setClassFilter(classFilter);
    }

    // 重写getPointcut。也就是获取切点的方法,因为需要对切点进行增强
    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }
}

BeanFactoryCacheOperationSourceAdvisor继承了AbstractBeanFactoryPointcutAdvisor,重写了Pointcut getPointcut()方法。

使用自定义的切点类CacheOperationSourcePointcut来作为切面的切点。而里面需要用到CacheOperationSource和ClassFilter。在BeanFactoryCacheOperationSourceAdvisor实例化时就已经设置。

而上面又执行了advisor.setAdvice(cacheInterceptor); 其实就是对这个切点添加了一个缓存拦截器,所以核心逻辑就在拦截器里面。

先再来看一下AnnotationCacheOperationSource

publicclass AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implementsSerializable{

    private finalbooleanpublicMethodsOnly;// 缓存注解解析集合private finalSet<CacheAnnotationParser>annotationParsers;publicAnnotationCacheOperationSource(){
        this(true);}publicAnnotationCacheOperationSource(booleanpublicMethodsOnly){
        this.publicMethodsOnly=publicMethodsOnly;// 重点:解析集合从SpringCacheAnnotationParser中获取,这个解析类就是解析注解的核心this.annotationParsers=Collections.singleton(new SpringCacheAnnotationParser());}// ...此处省略一万行代码// 判断是否时候选类@OverridepublicbooleanisCandidateClass(Class<?>targetClass){for(CacheAnnotationParser parser : this.annotationParsers){if(parser.isCandidateClass(targetClass)){returntrue;}
        }returnfalse;}// 重点:查找类级别的CacheOperation列表,就是看标注在类上的@Cacheable,@CacheEvict的集合@Override@Nullableprotected Collection<CacheOperation>findCacheOperations(Class<?>clazz){returndetermineCacheOperations(parser->parser.parseCacheAnnotations(clazz));}// 重点:查找方法级别的CacheOperation列表,就是看标注在方法上的@Cacheable,@CacheEvict的集合@Override@Nullableprotected Collection<CacheOperation>findCacheOperations(Method method){returndetermineCacheOperations(parser->parser.parseCacheAnnotations(method));}// ...此处省略一万行代码}

接着看一下SpringCacheAnnotationParser

publicclass SpringCacheAnnotationParser implements CacheAnnotationParser,Serializable{

    private static finalSet<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);}// 解析类级别的注解,封装为CacheOperation集合@Override@NullablepublicCollection<CacheOperation>parseCacheAnnotations(Class<?>type){
        DefaultCacheConfig defaultConfig=new DefaultCacheConfig(type);returnparseCacheAnnotations(defaultConfig,type);}// 解析方法级别的注解,封装为CacheOperation集合@Override@NullablepublicCollection<CacheOperation>parseCacheAnnotations(Method method){
        DefaultCacheConfig defaultConfig=new DefaultCacheConfig(method.getDeclaringClass());returnparseCacheAnnotations(defaultConfig,method);}// 解析注解@Nullableprivate Collection<CacheOperation>parseCacheAnnotations(DefaultCacheConfig cachingConfig,AnnotatedElement ae){
        Collection<CacheOperation>ops=parseCacheAnnotations(cachingConfig,ae,false);if(ops!=null&&ops.size()>1){// More than one operation found -> local declarations override interface-declared ones...Collection<CacheOperation>localOps=parseCacheAnnotations(cachingConfig,ae,true);if(localOps!=null){returnlocalOps;}
        }returnops;}// 具体解析注解的方法,包含了Cacheable,CacheEvict,CachePut,Caching等@Nullableprivate Collection<CacheOperation>parseCacheAnnotations(DefaultCacheConfig cachingConfig,AnnotatedElement ae,booleanlocalOnly){

        Collection<? extends Annotation>anns=(localOnly ?
                AnnotatedElementUtils.getAllMergedAnnotations(ae,CACHE_OPERATION_ANNOTATIONS):
                AnnotatedElementUtils.findAllMergedAnnotations(ae,CACHE_OPERATION_ANNOTATIONS));if(anns.isEmpty()){returnnull;}

        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));returnops;}// ...此处省略了一万行代码,基本这个类都是解析这些注解并封装为CacheOperation集合}

所以,SpringCacheAnnotationParser的作用就是将这些注解解析出来,并且封装为Collection<CacheOperation>,供其他地方使用。

ProxyCachingConfiguration总的来说就是声明了一个SpringCacheAnnotationParser和一个CacheInterceptor。在使用自定义的切点类,在切点前后切入一个CacheInterceptor来实现缓存的逻辑。

所以我们就找到的缓存的核心类CacheInterceptor,并且在构造拦截器时,传入了cacheManager作为缓存管理。

2.1.2、分析CacheInterceptor类

publicclass CacheInterceptor extends CacheAspectSupport implements MethodInterceptor,Serializable{// 拦截原始方法的执行,在方法前后增加横切逻辑@Override@NullablepublicObject invoke(final MethodInvocation invocation)throws Throwable {
        Method method=invocation.getMethod();CacheOperationInvoker aopAllianceInvoker=()->{
            try {returninvocation.proceed();}
            catch(Throwable ex){
                throw new CacheOperationInvoker.ThrowableWrapper(ex);}
        };Object target=invocation.getThis();Assert.state(target!=null,"Target must not be null");try {// 调用父类的execute方法,实现缓存的逻辑returnexecute(aopAllianceInvoker,target,method,invocation.getArguments());}
        catch(CacheOperationInvoker.ThrowableWrapper th){
            throw th.getOriginal();}
    }

}

可以看到,这个类很简单,就是拿到原方法的invoke,然后通过父类CacheAspectSupport的execute方法实现缓存逻辑。

关注CacheAspectSupport的execute方法

publicabstract 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();@Nullableprivate CacheOperationSource cacheOperationSource;private SingletonSupplier<KeyGenerator>keyGenerator=SingletonSupplier.of(SimpleKeyGenerator::new);@Nullableprivate SingletonSupplier<CacheResolver>cacheResolver;@Nullableprivate BeanFactory beanFactory;privatebooleaninitialized=false;@Nullableprotected Objectexecute(CacheOperationInvokerinvoker,Object target,Method method,Object[]args){// 如果bean已经被初始化了,则调用相应的缓存增强if(this.initialized){
            Class<?>targetClass=getTargetClass(target);CacheOperationSource cacheOperationSource=getCacheOperationSource();if(cacheOperationSource!=null){// 通过CacheOperationSource,获取所有的CacheOperation列表(就是那一堆标有缓存注解的类和方法的集合)Collection<CacheOperation>operations=cacheOperationSource.getCacheOperations(method,targetClass);if(!CollectionUtils.isEmpty(operations)){// 调用重载的execute方法returnexecute(invoker,method,new CacheOperationContexts(operations,method,args,target,targetClass));}
            }
        }// 否则,执行原方法返回即可returninvoker.invoke();}// 执行方法(核心)@Nullableprivate Objectexecute(final CacheOperationInvokerinvoker,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)){
                Objectkey=generateKey(context,CacheOperationExpressionEvaluator.NO_RESULT);Cache cache=context.getCaches().iterator().next();try {returnwrapCacheValue(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 methodreturninvokeOperation(invoker);}
        }// 如果存在@CacheEvict注解、并且标记为在调用前执行,调用processCacheEvicts进行缓存清除操作processCacheEvicts(contexts.get(CacheEvictOperation.class),true,CacheOperationExpressionEvaluator.NO_RESULT);// 如果存在Cacheable注解、调用findCachedItem查询缓存Cache.ValueWrapper cacheHit=findCachedItem(contexts.get(CacheableOperation.class));// 如果没有命中缓存,则调用cachePutRequests,存储在List<CachePutRequest>中,后续执行原始方法后会写入缓存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)){// If there are no put requests, just use the cache hitcacheValue=cacheHit.get();returnValue=wrapCacheValue(method,cacheValue);}// 缓存没有命中或者有@CachePut注解else{// 调用原始方法作为返回值returnValue=invokeOperation(invoker);// 将原始方法的返回值作为缓存值cacheValue=unwrapReturnValue(returnValue);}// 如果有@CachePut注解,则新增到cachePutRequestscollectPutRequests(contexts.get(CachePutOperation.class),cacheValue,cachePutRequests);// 缓存未命中或者存在@CachePut注解,调用CachePutRequest的apply方法将数据写入缓存for(CachePutRequest cachePutRequest : cachePutRequests){
            cachePutRequest.apply(cacheValue);}// 如果有@CacheEvict注解,并且标记为在调用后执行,则还需要执行清除缓存操作processCacheEvicts(contexts.get(CacheEvictOperation.class),false,cacheValue);returnreturnValue;}// 此处省略一万行代码}

总结来说,

  • 如果存在@CacheEvict注解,并且标记在方法执行前执行,就执行清除缓存相关操作。

  • 使用findCachedItem获取缓存,缓存没有命中,加入collectPutRequests,后续进行写入缓存操作。

  • 如果命中缓存并且没有@CachePut注解,获取命中的值作为方法的返回值

  • 如果没有命中,或者包含了@CachePut注解,加入collectPutRequests,后续进行写入缓存操作。

  • 遍历cachePutRequests,将需要写入缓存的数据写入缓存

  • 如果存在@CacheEvict注解,并且标记在方法执行后执行,就执行清除缓存相关操作。

还没完呢,因为我们定义的CacheManager怎么没有用到呢?我们继续跟踪下去,以get缓存方法为例子分析。

关注findCachedItem获取缓存方法

@Nullableprivate Cache.ValueWrapper findCachedItem(Collection<CacheOperationContext>contexts){// 遍历上下文列表Object result=CacheOperationExpressionEvaluator.NO_RESULT;for(CacheOperationContext context : contexts){if(isConditionPassing(context,result)){
            Objectkey=generateKey(context,result);// 根据生成的key获取缓存值Cache.ValueWrapper cached=findInCaches(context,key);if(cached!=null){returncached;}else{if(logger.isTraceEnabled()){
                    logger.trace("No cache entry for key '"+key+"' in cache(s) "+context.getCacheNames());}
            }
        }
    }returnnull;}

关注findInCaches获取缓存方法

@Nullableprivate Cache.ValueWrapper findInCaches(CacheOperationContext context,Objectkey){// 遍历缓存集合(getCaches),使用缓存的key去和获取缓存for(Cache cache : context.getCaches()){// 最终是使用Cache接口的get方法去获取缓存的Cache.ValueWrapper wrapper=doGet(cache,key);if(wrapper!=null){if(logger.isTraceEnabled()){
                logger.trace("Cache entry for key '"+key+"' found in cache '"+cache.getName()+"'");}returnwrapper;}
    }returnnull;}

关注doGet获取缓存方法

@Nullableprotected Cache.ValueWrapper doGet(Cache cache,Objectkey){
    try {returncache.get(key);}
    catch(RuntimeException ex){
        getErrorHandler().handleCacheGetError(ex,cache,key);returnnull;// If the exception is handled, return a cache miss}
}

我们发现,最终是通过Cache接口的get方法去获取缓存的,那么我们只要知道Cache集合对象是在哪里传入进来的就清楚了整个逻辑。

重新回到execute方法

@Nullableprotected Objectexecute(CacheOperationInvokerinvoker,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)){// 这里创建了一个CacheOperationContexts,我们有理由猜测CacheOperationContext.getCaches方法就是在这里面returnexecute(invoker,method,new CacheOperationContexts(operations,method,args,target,targetClass));}
        }
    }returninvoker.invoke();}

跟踪CacheOperationContexts

private class CacheOperationContexts {// 就是一个CacheOperationContext的集合,key是CacheOperation或者其子类private final MultiValueMap<Class<? extends CacheOperation>,CacheOperationContext>contexts;// 是否开启了sync=true属性private finalbooleansync;publicCacheOperationContexts(Collection<? extends CacheOperation>operations,Method method,Object[]args,Object target,Class<?>targetClass){// 根据CacheOperation集合,方法,参数创建了一个CacheOperationContext集合this.contexts=new LinkedMultiValueMap<>(operations.size());for(CacheOperation op : operations){// 重点:getOperationContext是具体创建CacheOperationContext的方法this.contexts.add(op.getClass(),getOperationContext(op,method,args,target,targetClass));}// 获取sync属性并赋值给this.syncthis.sync=determineSyncFlag(method);}publicCollection<CacheOperationContext>get(Class<? extends CacheOperation>operationClass){
        Collection<CacheOperationContext>result=this.contexts.get(operationClass);return(result!=null? result : Collections.emptyList());}publicbooleanisSynchronized(){returnthis.sync;}// ...此处省略了一万行代码}

关注getOperationContext创建CacheOperationContext

protected CacheOperationContext getOperationContext(CacheOperation operation,Method method,Object[]args,Object target,Class<?>targetClass){
    
    CacheOperationMetadata metadata=getCacheOperationMetadata(operation,method,targetClass);// 其实就是实例化一个CacheOperationContextreturnnew CacheOperationContext(metadata,args,target);}

其实就是拿到CacheOperationMetadata(CacheOperation的元数据信息),然后传给CacheOperationContext进行实例化CacheOperationContext。

关注CacheOperationContext的构造方法

上面实例化了CacheOperationContext,所以其构造方法内一定做了写什么事情。比如初始化操作。

// 缓存的集合private final Collection<? extends Cache>caches;publicCacheOperationContext(CacheOperationMetadata metadata,Object[]args,Object target){
    this.metadata=metadata;this.args=extractArgs(metadata.method,args);this.target=target;// 初始化了缓存名称列表和缓存集合this.caches=CacheAspectSupport.this.getCaches(this,metadata.cacheResolver);this.cacheNames=createCacheNames(this.caches);}

关注getCaches(获取缓存集合)

protected Collection<? extends Cache>getCaches(CacheOperationInvocationContext<CacheOperation>context,CacheResolver cacheResolver){// 这里可以知道是通过CacheResolver来获取的缓存集合Collection<? extends Cache>caches=cacheResolver.resolveCaches(context);if(caches.isEmpty()){
        throw new IllegalStateException("No cache could be resolved for '"+context.getOperation()+"' using resolver '"+cacheResolver+"'. At least one cache should be provided per cache operation.");}returncaches;}

关注CacheResolver以及实现类

@FunctionalInterfacepublicinterface CacheResolver {// 根据CacheOperationInvocationContext获取缓存集合Collection<? extends Cache>resolveCaches(CacheOperationInvocationContext<?>context);}

CacheResolver的抽象实现类AbstractCacheResolver

public abstract class AbstractCacheResolver implements CacheResolver, InitializingBean {

    // 这里就有CacheManager(缓存管理器)
	@Nullable
	private CacheManager cacheManager;
	
	protected AbstractCacheResolver() {
	}
	
	// 构造注入
	protected AbstractCacheResolver(CacheManager cacheManager) {
		this.cacheManager = cacheManager;
	}

	// set注入
	public void setCacheManager(CacheManager cacheManager) {
		this.cacheManager = cacheManager;
	}

    // 获取CacheManager
	public CacheManager getCacheManager() {
		Assert.state(this.cacheManager != null, "No CacheManager set");
		return this.cacheManager;
	}

	@Override
	public void afterPropertiesSet()  {
		Assert.notNull(this.cacheManager, "CacheManager is required");
	}
	
	// 获取缓存集合
	@Override
	public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
        // 先获取缓存名称
		Collection<String> cacheNames = getCacheNames(context);
		if (cacheNames == null) {
			return Collections.emptyList();
		}
		Collection<Cache> result = new ArrayList<>(cacheNames.size());
		// 遍历名称,通过CacheManager获取缓存,加入缓存集合
		for (String cacheName : cacheNames) {
			Cache cache = getCacheManager().getCache(cacheName);
			if (cache == null) {
				throw new IllegalArgumentException("Cannot find cache named '" +
						cacheName + "' for " + context.getOperation());
			}
			result.add(cache);
		}
		return result;
	}

	// 获取缓存名称集合
	@Nullable
	protected abstract Collection<String> getCacheNames(CacheOperationInvocationContext<?> context);

}

而我们的CacheManager默认使用SimpleCacheManager,我们注入了CustomRedisCacheManager, 所以会调用CustomRedisCacheManager的getCache方法获取缓存。

而getCache方法在父类AbstractCacheManager已经实现了。

// SpringCache最底层的数据结构就是以一个ConcurrentMap
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);

@Override
@Nullable
public Cache getCache(String name) {
    // 先从cacheMap中获取Cache, 获取到了直接返回
    Cache cache = this.cacheMap.get(name);
    if (cache != null) {
        return cache;
    }

    // 获取不到,使用双重检测所写入数据到cacheMap
    Cache missingCache = getMissingCache(name);
    if (missingCache != null) {
        // Fully synchronize now for missing cache registration
        synchronized (this.cacheMap) {
            cache = this.cacheMap.get(name);
            if (cache == null) {
                cache = decorateCache(missingCache);
                this.cacheMap.put(name, cache);
                updateCacheNames(name);
            }
        }
    }
    return cache;
}

到了这里,SpringCache的流程我们就真正的清楚了。

所以,SpringCache的源码分析就到此为止了。

25    2023-08-26 21:34:28    Spring 源码 自定义