精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

SpringCache源碼分析,你學會了嗎?

開發 前端
ProxyCachingConfiguration總的來說就是聲明了一個SpringCacheAnnotationParser和一個CacheInterceptor。在使用自定義的切點類,在切點前后切入一個CacheInterceptor來實現緩存的邏輯。

1、入口說明

@EnableCaching是開啟SpringCache的一個總開關,開啟時候我們的緩存相關注解才會生效,所以我們@EnableCaching開始作為入口進行分析,

2、分析@EnableCaching注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class) // 這里有一個Import,導入了一個Selector類
public @interface EnableCaching {

    // 是否創建cglib代理,默認為false, 也就是使用jdk動態代理
    boolean proxyTargetClass() default false;

    // 增強模式 默認使用JDK動態代理,引入cglib可以使用ASPECTJ
    AdviceMode mode() default AdviceMode.PROXY;

    // 排序字段
    int order() default Ordered.LOWEST_PRECEDENCE;

}

2.1、分析導入的CachingConfigurationSelector類

public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {

    // ...此處省略一萬行代碼

    // CachingConfigurationSelector繼承了AdviceModeImportSelector, 而AdviceModeImportSelector又實現了ImportSelector
    // 所以我們實現類selectImports,用于返回要導入的配置類列表
    @Override
    public String[] selectImports(AdviceMode adviceMode) {
        // 如果是jdk動態代理,走getProxyImports邏輯。如果是cglib動態代理,走getAspectJImports邏輯
        switch (adviceMode) {
            case PROXY:
                return getProxyImports();
            case ASPECTJ:
                return getAspectJImports();
            default:
                return null;
        }
    }

    // 獲取要進行自動配置的配置類
    private String[] getProxyImports() {
        List<String> result = new ArrayList<>(3);
        // 這里添加了兩個類,AutoProxyRegistrar(自動代理注冊器),ProxyCachingConfiguration(代理緩存配置類)
        // AutoProxyRegistrar點進去可以發現,里面其實就是提供了registerBeanDefinitions方法用于注冊BeanDefinition
        result.add(AutoProxyRegistrar.class.getName());
        // ProxyCachingConfiguration點進去發現,配置類緩存相關的一些Bean(就是SpringCache的一些核心Bean)
        result.add(ProxyCachingConfiguration.class.getName());
        if (jsr107Present && jcacheImplPresent) {
            result.add(PROXY_JCACHE_CONFIGURATION_CLASS);
        }
        return StringUtils.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)
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {

    // BeanFactoryCacheOperationSourceAdvisor是對CacheOperationSource進行增強,其實就是添加一個攔截器,用于獲取相關緩存的注解信息
    // 所以有些邏輯會在CacheInterceptor里
    @Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryCacheOperationSourceAdvisor 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"));
        }
        return advisor;
    }

    // 定義一個CacheOperationSource,主要用于獲取類或者方法上的注解。
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public CacheOperationSource cacheOperationSource() {
        return new AnnotationCacheOperationSource();
    }

    // 定義了一個攔截器,該攔截器用于用于攔截緩存相關注解,做AOP操作。比如先查詢緩存,查詢到直接返回,查詢不到就執行方法體,將結果寫入緩存。
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public CacheInterceptor cacheInterceptor(CacheOperationSource cacheOperationSource) {
        CacheInterceptor interceptor = new CacheInterceptor();
        // 緩存攔截器在這里注入了cacheManager(緩存管理器)
        interceptor.configure(this.errorHandler, this.keyGenerator, this.cacheResolver, this.cacheManager);
        interceptor.setCacheOperationSource(cacheOperationSource);
        return interceptor;
    }

}

來分析一下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

public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implements Serializable {

    private final boolean publicMethodsOnly;

    // 緩存注解解析集合
    private final Set<CacheAnnotationParser> annotationParsers;
    
    public AnnotationCacheOperationSource() {
        this(true);
    }
    
    public AnnotationCacheOperationSource(boolean publicMethodsOnly) {
        this.publicMethodsOnly = publicMethodsOnly;
        // 重點:解析集合從SpringCacheAnnotationParser中獲取,這個解析類就是解析注解的核心
        this.annotationParsers = Collections.singleton(new SpringCacheAnnotationParser());
    }
    
    // ...此處省略一萬行代碼

    // 判斷是否時候選類
    @Override
    public boolean isCandidateClass(Class<?> targetClass) {
        for (CacheAnnotationParser parser : this.annotationParsers) {
            if (parser.isCandidateClass(targetClass)) {
                return true;
            }
        }
        return false;
    }

    // 重點:查找類級別的CacheOperation列表,就是看標注在類上的@Cacheable,@CacheEvict的集合
    @Override
    @Nullable
    protected Collection<CacheOperation> findCacheOperations(Class<?> clazz) {
        return determineCacheOperations(parser -> parser.parseCacheAnnotations(clazz));
    }

    // 重點:查找方法級別的CacheOperation列表,就是看標注在方法上的@Cacheable,@CacheEvict的集合
    @Override
    @Nullable
    protected Collection<CacheOperation> findCacheOperations(Method method) {
        return determineCacheOperations(parser -> parser.parseCacheAnnotations(method));
    }
    
    // ...此處省略一萬行代碼
}

接著看一下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);
    }

    // 解析類級別的注解,封裝為CacheOperation集合
    @Override
    @Nullable
    public Collection<CacheOperation> parseCacheAnnotations(Class<?> type) {
        DefaultCacheConfig defaultConfig = new DefaultCacheConfig(type);
        return parseCacheAnnotations(defaultConfig, type);
    }

    // 解析方法級別的注解,封裝為CacheOperation集合
    @Override
    @Nullable
    public Collection<CacheOperation> parseCacheAnnotations(Method method) {
        DefaultCacheConfig defaultConfig = new DefaultCacheConfig(method.getDeclaringClass());
        return parseCacheAnnotations(defaultConfig, method);
    }

    // 解析注解
    @Nullable
    private 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) {
                return localOps;
            }
        }
        return ops;
    }

    // 具體解析注解的方法,包含了Cacheable,CacheEvict,CachePut,Caching等
    @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;
    }
    // ...此處省略了一萬行代碼,基本這個類都是解析這些注解并封裝為CacheOperation集合
}

所以,SpringCacheAnnotationParser的作用就是將這些注解解析出來,并且封裝為Collection<CacheOperation>,供其他地方使用。

ProxyCachingConfiguration總的來說就是聲明了一個SpringCacheAnnotationParser和一個CacheInterceptor。在使用自定義的切點類,在切點前后切入一個CacheInterceptor來實現緩存的邏輯。

所以我們就找到的緩存的核心類CacheInterceptor,并且在構造攔截器時,傳入了cacheManager作為緩存管理。

2.1.2、分析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 {
            // 調用父類的execute方法,實現緩存的邏輯
            return execute(aopAllianceInvoker, target, method, invocation.getArguments());
        }
        catch (CacheOperationInvoker.ThrowableWrapper th) {
            throw th.getOriginal();
        }
    }

}

可以看到,這個類很簡單,就是拿到原方法的invoke,然后通過父類CacheAspectSupport的execute方法實現緩存邏輯。

關注CacheAspectSupport的execute方法

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;

    @Nullable
    private BeanFactory beanFactory;

    private boolean initialized = false;

    @Nullable
    protected Object execute(CacheOperationInvoker invoker, 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方法
                    return execute(invoker, method,
                            new CacheOperationContexts(operations, method, args, target, targetClass));
                }
            }
        }

        // 否則,執行原方法返回即可
        return invoker.invoke();
    }


    // 執行方法(核心)
    @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, 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);
            }
        }

        // 如果存在@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 hit
            cacheValue = cacheHit.get();
            returnValue = wrapCacheValue(method, cacheValue);
        }
        // 緩存沒有命中或者有@CachePut注解
        else {
            // 調用原始方法作為返回值
            returnValue = invokeOperation(invoker);
            // 將原始方法的返回值作為緩存值
            cacheValue = unwrapReturnValue(returnValue);
        }

        // 如果有@CachePut注解,則新增到cachePutRequests
        collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);

        // 緩存未命中或者存在@CachePut注解,調用CachePutRequest的apply方法將數據寫入緩存
        for (CachePutRequest cachePutRequest : cachePutRequests) {
            cachePutRequest.apply(cacheValue);
        }

        // 如果有@CacheEvict注解,并且標記為在調用后執行,則還需要執行清除緩存操作
        processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);

        return returnValue;
    }
    // 此處省略一萬行代碼
}

總結來說,

  • 如果存在@CacheEvict注解,并且標記在方法執行前執行,就執行清除緩存相關操作。
  • 使用findCachedItem獲取緩存,緩存沒有命中,加入collectPutRequests,后續進行寫入緩存操作。
  • 如果命中緩存并且沒有@CachePut注解,獲取命中的值作為方法的返回值
  • 如果沒有命中,或者包含了@CachePut注解,加入collectPutRequests,后續進行寫入緩存操作。
  • 遍歷cachePutRequests,將需要寫入緩存的數據寫入緩存
  • 如果存在@CacheEvict注解,并且標記在方法執行后執行,就執行清除緩存相關操作。

還沒完呢,因為我們定義的CacheManager怎么沒有用到呢?我們繼續跟蹤下去,以get緩存方法為例子分析。

關注findCachedItem獲取緩存方法

@Nullable
private Cache.ValueWrapper findCachedItem(Collection<CacheOperationContext> contexts) {
    // 遍歷上下文列表
    Object result = CacheOperationExpressionEvaluator.NO_RESULT;
    for (CacheOperationContext context : contexts) {
        if (isConditionPassing(context, result)) {
            Object key = generateKey(context, result);
            // 根據生成的key獲取緩存值
            Cache.ValueWrapper cached = findInCaches(context, key);
            if (cached != null) {
                return cached;
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("No cache entry for key '" + key + "' in cache(s) " + context.getCacheNames());
                }
            }
        }
    }
    return null;
}

關注findInCaches獲取緩存方法

@Nullable
private Cache.ValueWrapper findInCaches(CacheOperationContext context, Object key) {
    // 遍歷緩存集合(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() + "'");
            }
            return wrapper;
        }
    }
    return null;
}

關注doGet獲取緩存方法

@Nullable
protected Cache.ValueWrapper doGet(Cache cache, Object key) {
    try {
        return cache.get(key);
    }
    catch (RuntimeException ex) {
        getErrorHandler().handleCacheGetError(ex, cache, key);
        return null;  // If the exception is handled, return a cache miss
    }
}

我們發現,最終是通過Cache接口的get方法去獲取緩存的,那么我們只要知道Cache集合對象是在哪里傳入進來的就清楚了整個邏輯。

重新回到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)) {
                // 這里創建了一個CacheOperationContexts,我們有理由猜測CacheOperationContext.getCaches方法就是在這里面
                return execute(invoker, method,
                        new CacheOperationContexts(operations, method, args, target, targetClass));
            }
        }
    }

    return invoker.invoke();
}

跟蹤CacheOperationContexts

private class CacheOperationContexts {
    // 就是一個CacheOperationContext的集合,key是CacheOperation或者其子類
    private final MultiValueMap<Class<? extends CacheOperation>, CacheOperationContext> contexts;

    // 是否開啟了sync=true屬性
    private final boolean sync;

    public CacheOperationContexts(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.sync
        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;
    }
    
    // ...此處省略了一萬行代碼
}

關注getOperationContext創建CacheOperationContext

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

其實就是拿到CacheOperationMetadata(CacheOperation的元數據信息),然后傳給CacheOperationContext進行實例化CacheOperationContext。

關注CacheOperationContext的構造方法

上面實例化了CacheOperationContext,所以其構造方法內一定做了寫什么事情。比如初始化操作。

// 緩存的集合
private final Collection<? extends Cache> caches;

public CacheOperationContext(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.");
    }
    return caches;
}

關注CacheResolver以及實現類

@FunctionalInterface
public interface 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的源碼分析就到此為止了。

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2022-10-18 17:59:46

Bootstrap源碼父類

2023-05-08 07:41:07

Linux內核ELF文件

2023-03-08 08:42:55

MySQLcost量化

2022-09-22 12:03:14

網絡安全事件

2024-01-19 08:25:38

死鎖Java通信

2023-01-10 08:43:15

定義DDD架構

2024-02-04 00:00:00

Effect數據組件

2023-07-26 13:11:21

ChatGPT平臺工具

2023-06-27 07:21:51

前端開發坑點

2023-08-01 12:51:18

WebGPT機器學習模型

2024-01-02 12:05:26

Java并發編程

2024-07-31 08:26:47

2022-11-06 14:46:28

腳本windows文件

2024-09-27 10:27:50

2023-01-30 09:01:54

圖表指南圖形化

2024-08-06 09:47:57

2022-07-08 09:27:48

CSSIFC模型

2023-10-10 11:04:11

Rust難點內存

2024-07-31 08:39:45

Git命令暫存區

2023-12-12 08:02:10

點贊
收藏

51CTO技術棧公眾號

欧美午夜性生活| 加勒比av一区二区| 久久亚洲精精品中文字幕早川悠里 | 国产亚洲一区二区手机在线观看 | 日本国产高清不卡| 青青草原网站在线观看| 国产免费www| 青青草久久爱| 一级中文字幕一区二区| 国产欧美一区二区三区久久人妖| 欧美高清性xxxx| gogo高清在线播放免费| 午夜国产一区| 欧美一区二区国产| 偷拍盗摄高潮叫床对白清晰| 中文字幕av久久爽| 国产一区二区三区四区| 色婷婷激情综合| 欧美日韩国产免费一区二区三区| 日韩不卡视频在线| 久久不见久久见免费视频7| 丁香五六月婷婷久久激情| 国内视频一区| 亚洲综合一二三| 欧美尿孔扩张虐视频| 欧美日本免费一区二区三区| 曰韩不卡视频| 国产乱叫456在线| 欧美黄免费看| 中文字幕精品久久久久| 欧美国产日韩另类| 少妇视频在线| 97精品电影院| 国产精品久久久久久久电影| 中文天堂资源在线| 电影中文字幕一区二区| 亚洲一区二区中文在线| 九色一区二区| 亚洲性猛交富婆| 91精品国产91久久久久久密臀 | 午夜dv内射一区二区| 国产免费视频在线| 久久99久久99小草精品免视看| 丝袜亚洲另类欧美重口| 国产乱女淫av麻豆国产| 午夜激情成人网| 欧美日韩精品二区| 奇米精品一区二区三区| 国产小视频在线观看| 美国一区二区三区在线播放| 欧美成人国产va精品日本一级| 久久久久国产免费| 成人直播视频| 亚洲免费伊人电影| 久久伦理网站| 天堂网www中文在线| 久久精品国产精品青草| 国产精品久久精品| 在线观看av大片| 亚洲电影在线| 日韩中文字幕在线免费观看| 91精品人妻一区二区三区四区| 中文字幕在线高清| 亚洲嫩草精品久久| 91精品国产毛片武则天| 丁香在线视频| 欧美国产一区在线| 黑人巨大精品欧美一区二区小视频| 久久久久久无码精品大片| 羞羞视频在线观看欧美| 久久99久久久久久久噜噜| 级毛片内射视频| 风间由美中文字幕在线看视频国产欧美| 日本道免费精品一区二区三区| 激情六月天婷婷| www黄在线观看| 99久久久精品| 亚洲影视中文字幕| 在线观看国产黄| 国产真实乱偷精品视频免| 欧美一区二三区| 久久久精品国产sm调教网站| 成人一二三区| 亚洲欧洲免费视频| 国产制服丝袜在线| 欧美亚洲高清| 欧美精品情趣视频| www.国产色| 精品一区二区久久| 国产亚洲情侣一区二区无| 韩日在线视频| 亚洲精品乱码久久久久久久久 | 欧美日韩在线视频一区| 亚洲女人毛片| 日韩国产福利| www.欧美.com| 亚洲国产综合自拍| 国产丝袜精品丝袜| 一区二区三区在线观看欧美| www.日本在线播放| 男女羞羞视频在线观看| 亚洲精品福利视频网站| 日日鲁鲁鲁夜夜爽爽狠狠视频97| 成人三级小说| 欧美日韩精品电影| av2014天堂网| 日韩成人av在线资源| 亚洲国产精品久久久久秋霞蜜臀| 苍井空张开腿实干12次| 久久91精品| 久久69精品久久久久久国产越南| 秋霞精品一区二区三区| 亚洲一区不卡| 情事1991在线| 肥臀熟女一区二区三区| 成人精品在线视频观看| 国产二区不卡| 欧性猛交ⅹxxx乱大交| 成人免费高清在线观看| 亚洲精品欧美精品| 丁香花高清在线观看完整版| 欧美日韩一级大片网址| 男生操女生视频在线观看| 日韩黄色三级在线观看| 欧美日韩成人综合在线一区二区| 中文字幕人妻一区二区三区| 激情小说一区| 日韩av在线资源| 成人免费毛片糖心| 色天天久久综合婷婷女18| 色狠狠av一区二区三区香蕉蜜桃| 日韩成人高清视频| 久久激情婷婷| 成人www视频在线观看| 国内精品久久久久久久久久久 | 牛牛热在线视频| 久久亚洲精精品中文字幕早川悠里| 蜜桃视频一区二区在线观看| 色综合视频一区二区三区44| 在线观看免费高清视频97| 黄色录像免费观看| 亚洲国产高清视频| 日韩av免费在线播放| 中文字幕网址在线| 国产视频视频一区| 青青在线免费视频| 粉嫩91精品久久久久久久99蜜桃| 91麻豆精品国产综合久久久久久| 人妻 丝袜美腿 中文字幕| 我不卡伦不卡影院| 午夜欧美不卡精品aaaaa| 小泽玛利亚一区二区三区视频| 91社区在线播放| 一区二区三区偷拍| 日韩伦理一区二区| 精品久久久999| 羞羞影院体验区| 91色视频在线| 国产欧美高清在线| 亚洲精品福利| 中文在线资源观看视频网站免费不卡| 国产性生活视频| 国产成人亚洲综合a∨婷婷| 免费精品视频一区| 在线视频中文字幕第一页| 一本色道亚洲精品aⅴ| 国产特黄级aaaaa片免| 欧美精选一区| 国产精品视频自在线| 色屁屁草草影院ccyycom| 国产精品美女久久久久久| 日本在线xxx| 另类视频一区二区三区| 亚洲一级一级97网| 91看片在线播放| 91亚洲精品久久久蜜桃网站| 超碰影院在线观看| 91精品秘密在线观看| 国产精品自拍首页| 黄色在线观看网站| 在线观看视频一区二区| 日韩av电影免费在线观看| 粉嫩av蜜桃av蜜臀av| 91久久综合| 水蜜桃亚洲一二三四在线| 成年男女免费视频网站不卡| 99re66热这里只有精品8| 亚洲第一区中文99精品| 国产aaaaaaaaa| 国产精品毛片| 五码日韩精品一区二区三区视频| 97精品资源在线观看| 国产一区二区三区在线观看视频| 中文字幕第一页在线播放| 亚洲精品日产精品乱码不卡| 国内精品久久99人妻无码| 精久久久久久久久久久| 69堂免费视频| 亚洲精品电影| 国产亚洲欧美一区二区| 亚洲男男av| 日本午夜人人精品| 日本色护士高潮视频在线观看| 亚洲乱码国产乱码精品精天堂| 欧美成人aaaaⅴ片在线看| 日本一区二区不卡视频| 男女污污的视频| 天堂网av成人| 亚洲影院污污.| 日本一区二区三区视频在线| 亚洲人成网站777色婷婷| 国产哺乳奶水91在线播放| 91激情五月电影| 五月婷婷中文字幕| 亚洲综合一二三区| 九九热视频在线免费观看| 久久久久久久久久久久久夜| 国产一区二区在线视频播放| 久久久久蜜桃| 四虎一区二区| 亚洲精品亚洲人成在线观看| 欧美中文在线免费| 国产盗摄在线视频网站| 久久亚洲国产成人| 亚洲精品字幕在线观看| 亚洲已满18点击进入久久| 国产精品综合激情| 久久精品在这里| 国产真实乱人偷精品| 国产成人综合视频| 日本亚洲一区二区三区| 伊人久久亚洲热| 9l视频自拍9l视频自拍| 国产高清一区二区| 亚洲欧洲另类精品久久综合| 国产剧情在线观看一区| 欧美一级二级三级| 97久久中文字幕| 国产精品免费在线免费| 在线视频中文字幕第一页| 日韩在线观看高清| 在线看的av网站| 日韩免费高清视频| 伊人中文字幕在线观看 | 欧美性猛交xxxxx少妇| 粉嫩av亚洲一区二区图片| 三级4级全黄60分钟| 夜夜嗨av一区二区三区网站四季av| 欧美成熟毛茸茸复古| 伦理一区二区三区| 精品一区久久久| 伊人成综合网伊人222| 欧美大香线蕉线伊人久久国产精品| 久久这里只有精品一区二区| 国产精品成人观看视频免费| 精品国产一区二区三区不卡蜜臂| 国产精品一区二区三区在线观| 乱亲女h秽乱长久久久| 蜜桃成人在线| 欧美综合一区| 中文字幕一区二区中文字幕 | www.日韩欧美| √天堂8在线网| 欧美激情视频网址| www 日韩| 日韩视频欧美视频| av超碰免费在线| 午夜精品久久久久久久白皮肤 | 国产人妖伪娘一区91| 日韩av黄色| 懂色中文一区二区三区在线视频 | 日韩乱码在线视频| 国产又粗又猛又色又| 69久久夜色精品国产69蝌蚪网| 精品人妻无码一区二区| 欧美亚洲动漫另类| 日韩精品一区二区在线播放| 欧美性猛交xxxx乱大交3| 亚洲精品无码久久久久| 欧美一卡2卡三卡4卡5免费| 欧美亚洲精品在线观看| 亚洲天堂免费在线| 在线观看的网站你懂的| 91精品国产91久久久久久| 婷婷丁香在线| 2023亚洲男人天堂| 亚洲精品tv| 久久精品国产第一区二区三区最新章节| 精品国产一区探花在线观看 | 亚洲精品乱码久久久久久黑人| 亚洲黄色三级视频| 7777精品伊人久久久大香线蕉的| 天堂在线视频网站| 日韩一区av在线| www.综合| 91久热免费在线视频| av亚洲一区二区三区| 亚洲iv一区二区三区| 亚洲精品aaaaa| 免费的一级黄色片| 免费成人在线视频观看| 日韩肉感妇bbwbbwbbw| 国产91在线观看丝袜| 山东少妇露脸刺激对白在线| 亚洲精品久久久蜜桃| 在线观看免费高清视频| 日韩精品免费综合视频在线播放| 国产成人l区| 欧美乱人伦中文字幕在线| 日韩电影av| 国产精品久久久久久超碰| 成人av地址| 黄色国产精品一区二区三区| 999国产精品永久免费视频app| 日本精品免费在线观看| 粉嫩嫩av羞羞动漫久久久| 国产精品精品软件男同| 欧美在线观看你懂的| 天天躁日日躁狠狠躁喷水| 欧美日韩爱爱视频| 国产精品igao视频网网址不卡日韩| 日韩成人av电影在线| 日韩视频不卡| 欧美激情一区二区三区p站| 亚洲女同一区二区| 国产又黄又大又粗的视频| 在线日韩精品视频| 日本一区免费网站| 品久久久久久久久久96高清| 国产精品综合| 星空大象在线观看免费播放| 亚洲午夜成aⅴ人片| 国产xxxxxx| 欧美肥婆姓交大片| 欧美一区一区| 国产日韩欧美精品| 欧美午夜视频| 亚洲综合中文网| 91在线免费播放| 日韩免费在线视频观看| 亚洲成人精品av| 2021天堂中文幕一二区在线观| 成人午夜电影免费在线观看| 午夜天堂精品久久久久| 男女视频在线观看网站| 91免费视频网址| 在线观看免费国产视频| 亚洲精品国产美女| 三级中文字幕在线观看| 国产日韩精品视频| 99精品网站| 自拍一级黄色片| 亚洲一区二区影院| 日本高清视频免费看| 68精品久久久久久欧美| 久久97视频| 超碰在线97免费| 中文字幕色av一区二区三区| 亚洲精品1区2区3区| 精品无人区太爽高潮在线播放 | 伊人久久亚洲热| 狠狠人妻久久久久久综合蜜桃| 欧美日韩国产限制| 电影在线高清| 亚洲伊人久久综合| 99在线|亚洲一区二区| 草草影院第一页| 欧美美女一区二区| 欧美捆绑视频| 国产精品自产拍在线观看| 欧美1级片网站| 中文字幕制服丝袜| 日韩欧美国产免费播放| 北岛玲一区二区三区| 亚洲va欧美va国产综合久久| 影音先锋亚洲电影| 性欧美一区二区| 日韩欧美在线视频日韩欧美在线视频 | 精品久久人人做人人爰| 午夜精品一区| 日韩美女主播视频| 欧美电影《轻佻寡妇》| 亚洲欧美激情一区二区三区| 高跟丝袜一区二区三区| 91青青在线视频| 国产精品一区二区欧美| 日本vs亚洲vs韩国一区三区二区| 亚洲天堂成人av| 欧美日韩国产精品成人| wwww亚洲| 亚洲欧美日本国产有色| 成人av资源站| 国产午夜福利片| 欧美变态凌虐bdsm| 欧美free嫩15| 国产肉体ⅹxxx137大胆| 国产精品 欧美精品| 久久久蜜桃一区二区| 久久99精品久久久久久青青91| 国产一卡不卡|