Spring 緩存切面

緩存切面:【通知+目標方法調用】

緩存操作執行過程:
1)如果是同步調用【sync=true】,則首先嚐試從緩存中讀取數據,讀取到則直接返回;
否則執行目標方法,將結果緩存後返回。
2)如果不是同步調用【sync=false,默認】
2-1)執行 beforeInvocation=true 並滿足條件的 CacheEvict 操作,
2-2)從緩存操作上下文中根據緩存鍵讀取數據【存在 @Cacheable 註解】,
    緩存未命中:則收集 @Cacheable 緩存寫入請求,並執行目標方法。
    緩存命中且無滿足條件的 CachePut 操作:直接讀取緩存結果【目標方法不會被執行】。
2-3)從 @CachePut 註解上收集顯式的緩存寫入操作。
2-4)執行從 @Cacheable 和 @CachePut 上收集到的緩存寫入操作。
2-5)執行 beforeInvocation=false 並滿足條件的 CacheEvict 操作。

最佳實踐:
@CachePut 註解使用在寫入和更新操作上
@Cacheable 註解使用在讀取操作上
@CacheEvict 註解使用在刪除操作上
/**
 *  執行緩存操作的基礎組件,附加緩存異常處理器
 */
public abstract class AbstractCacheInvoker {

    protected SingletonSupplier<CacheErrorHandler> errorHandler;

    protected AbstractCacheInvoker() {
        // 不做任何事情的異常處理器
        this.errorHandler = SingletonSupplier.of(SimpleCacheErrorHandler::new);
    }

    protected AbstractCacheInvoker(CacheErrorHandler errorHandler) {
        this.errorHandler = SingletonSupplier.of(errorHandler);
    }

    public void setErrorHandler(CacheErrorHandler errorHandler) {
        this.errorHandler = SingletonSupplier.of(errorHandler);
    }

    public CacheErrorHandler getErrorHandler() {
        return this.errorHandler.obtain();
    }

    /**
     *  執行緩存 Get 操作
     */
    @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
        }
    }

    /**
     *  執行緩存 Put 操作
     */
    protected void doPut(Cache cache, Object key, @Nullable Object result) {
        try {
            cache.put(key, result);
        }
        catch (RuntimeException ex) {
            getErrorHandler().handleCachePutError(ex, cache, key, result);
        }
    }

    /**
     *  執行緩存 Evict 操作
     */
    protected void doEvict(Cache cache, Object key) {
        try {
            cache.evict(key);
        }
        catch (RuntimeException ex) {
            getErrorHandler().handleCacheEvictError(ex, cache, key);
        }
    }

    /**
     *  執行緩存 Clear 操作
     */
    protected void doClear(Cache cache) {
        try {
            cache.clear();
        }
        catch (RuntimeException ex) {
            getErrorHandler().handleCacheClearError(ex, cache);
        }
    }
}

/**
 *  緩存切面的基礎類
 */
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;
    /**
     *  單例鍵生成器  Supplier
     */
    private SingletonSupplier<KeyGenerator> keyGenerator = SingletonSupplier.of(SimpleKeyGenerator::new);
    /**
     *  單例緩存解析器 Supplier
     */
    @Nullable
    private SingletonSupplier<CacheResolver> cacheResolver;
    /**
     *  Bean 工廠【DefaultListableBeanFactory】
     */
    @Nullable
    private BeanFactory beanFactory;
    /**
     *  切面是否已經初始化
     */
    private boolean initialized = false;

    @Override
    public void afterSingletonsInstantiated() {
        if (getCacheResolver() == null) {
            // Lazily initialize cache resolver via default cache manager...
            Assert.state(beanFactory != null, "CacheResolver or BeanFactory must be set on cache aspect");
            try {
                // 基於緩存管理器創建緩存解析器,並寫入
                setCacheManager(beanFactory.getBean(CacheManager.class));
            }
            catch (final 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.");
            }
            catch (final 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.");
            }
        }
        initialized = true;
    }

    /**
     *  基於緩存操作執行上下文和緩存解析器讀取緩存集合
     */
    protected Collection<? extends Cache> getCaches(
            CacheOperationInvocationContext<CacheOperation> context, CacheResolver cacheResolver) {
        final 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;
    }

        @Nullable
    protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
        // 緩存切面是否啓用
        if (initialized) {
            // 讀取目標類 Class
            final Class<?> targetClass = getTargetClass(target);
            // 讀取緩存操作源
            final CacheOperationSource cacheOperationSource = getCacheOperationSource();
            if (cacheOperationSource != null) {
                // 讀取目標方法上的所有緩存操作
                final 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();
    }

    protected CacheOperationContext getOperationContext(
            CacheOperation operation, Method method, Object[] args, Object target, Class<?> targetClass) {
        // 讀取緩存操作元數據
        final CacheOperationMetadata metadata = getCacheOperationMetadata(operation, method, targetClass);
        return new CacheOperationContext(metadata, args, target);
    }

    protected CacheOperationMetadata getCacheOperationMetadata(
            CacheOperation operation, Method method, Class<?> targetClass) {
        // 緩存操作的緩存鍵
        final CacheOperationCacheKey cacheKey = new CacheOperationCacheKey(operation, method, targetClass);
        // 已經創建過則直接讀取
        CacheOperationMetadata metadata = metadataCache.get(cacheKey);
        if (metadata == null) {
            KeyGenerator operationKeyGenerator;
            //  1)緩存操作配置了鍵生成器
            if (StringUtils.hasText(operation.getKeyGenerator())) {
                // 寫入指定 bean 名稱的鍵生成器
                operationKeyGenerator = getBean(operation.getKeyGenerator(), KeyGenerator.class);
            }
            else {
                // 寫入 SimpleKeyGenerator
                operationKeyGenerator = getKeyGenerator();
            }
            CacheResolver operationCacheResolver;
            //  2)緩存操作配置了緩存解析器
            if (StringUtils.hasText(operation.getCacheResolver())) {
                // 寫入指定 bean 名稱的緩存解析器
                operationCacheResolver = getBean(operation.getCacheResolver(), CacheResolver.class);
            }
            // 3)緩存操作配置了緩存管理器
            else if (StringUtils.hasText(operation.getCacheManager())) {
                final CacheManager cacheManager = getBean(operation.getCacheManager(), CacheManager.class);
                // 基於目標緩存管理器創建 SimpleCacheResolver 並寫入
                operationCacheResolver = new SimpleCacheResolver(cacheManager);
            }
            else {
                // 寫入默認的 SimpleCacheResolver
                operationCacheResolver = getCacheResolver();
                Assert.state(operationCacheResolver != null, "No CacheResolver/CacheManager set");
            }
            // 創建緩存操作元數據並加入緩存
            metadata = new CacheOperationMetadata(operation, method, targetClass,
                    operationKeyGenerator, operationCacheResolver);
            metadataCache.put(cacheKey, metadata);
        }
        return metadata;
    }

    protected <T> T getBean(String beanName, Class<T> expectedType) {
        if (beanFactory == null) {
            throw new IllegalStateException(
                    "BeanFactory must be set on cache aspect for " + expectedType.getSimpleName() + " retrieval");
        }
        return BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, expectedType, beanName);
    }

    /**
     * Clear the cached metadata.
     */
    protected void clearMetadataCache() {
        metadataCache.clear();
        evaluator.clear();
    }

    @Nullable
    protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
        // 緩存切面是否啓用
        if (initialized) {
            // 讀取目標類 Class
            final Class<?> targetClass = getTargetClass(target);
            // 讀取緩存操作源
            final CacheOperationSource cacheOperationSource = getCacheOperationSource();
            if (cacheOperationSource != null) {
                // 讀取目標方法上的所有緩存操作
                final 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();
    }

    /**
     *  執行底層目標方法
     */
    protected Object invokeOperation(CacheOperationInvoker invoker) {
        return invoker.invoke();
    }

    private Class<?> getTargetClass(Object target) {
        return AopProxyUtils.ultimateTargetClass(target);
    }

    @Nullable
    private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
        // 1)同步調用的特殊處理
        if (contexts.isSynchronized()) {
            final CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();
            // 緩存操作條件是否匹配
            if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
                // 計算緩存鍵
                final Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
                // 讀取緩存
                final Cache cache = context.getCaches().iterator().next();
                try {
                    /**
                     *  如果緩存已經存在,則直接讀取;否則執行目標方法,並將其結果值加入緩存。
                     *  並將結果值進行封裝
                     */
                    return wrapCacheValue(method, cache.get(key, () -> unwrapReturnValue(invokeOperation(invoker))));
                }
                catch (final Cache.ValueRetrievalException ex) {
                    throw (CacheOperationInvoker.ThrowableWrapper) ex.getCause();
                }
            }
            else {
                //  緩存操作條件不匹配,則直接調用目標方法
                return invokeOperation(invoker);
            }
        }


        /**
         *  1)處理方法調用前的緩存清除
         *  如果指定了 CacheEvictOperation 操作 && beforeInvocation==true && 滿足緩存操作條件,則執行緩存清除
         */
        processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
                CacheOperationExpressionEvaluator.NO_RESULT);

        /**
         *  2)從緩存操作上下文中,讀取指定緩存鍵相關的條目
         */
        final Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));

        // 緩存未命中,則收集 @Cacheable 緩存寫入請求【結果變量 result 不可用】
        final List<CachePutRequest> cachePutRequests = new LinkedList<>();
        if (cacheHit == null) {
            collectPutRequests(contexts.get(CacheableOperation.class),
                    CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
        }

        Object cacheValue;
        Object returnValue;
        // 1)命中緩存
        if (cacheHit != null && !hasCachePut(contexts)) {
            // 無 CachePut 操作,則直接使用命中的緩存結果
            cacheValue = cacheHit.get();
            returnValue = wrapCacheValue(method, cacheValue);
        }
        else {
            // 緩存未命中,則執行目標方法
            returnValue = invokeOperation(invoker);
            cacheValue = unwrapReturnValue(returnValue);
        }

        // 收集所有顯式的 @CachePut 操作
        collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);

        // 執行從 @CachePut or @Cacheable 收集到的緩存寫入操作
        for (final CachePutRequest cachePutRequest : cachePutRequests) {
            cachePutRequest.apply(cacheValue);
        }

        // 執行方法執行後的緩存清除操作
        processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);
        return returnValue;
    }

    @Nullable
    private Object wrapCacheValue(Method method, @Nullable Object cacheValue) {
        // 方法的返回結果爲 Optional,則進行封裝
        if (method.getReturnType() == Optional.class &&
                (cacheValue == null || cacheValue.getClass() != Optional.class)) {
            return Optional.ofNullable(cacheValue);
        }
        return cacheValue;
    }

    @Nullable
    private Object unwrapReturnValue(Object returnValue) {
        return ObjectUtils.unwrapOptional(returnValue);
    }

    private boolean hasCachePut(CacheOperationContexts contexts) {
        // 讀取 CachePutOperation 的上下文集合
        final Collection<CacheOperationContext> cachePutContexts = contexts.get(CachePutOperation.class);
        final Collection<CacheOperationContext> excluded = new ArrayList<>();
        for (final CacheOperationContext context : cachePutContexts) {
            try {
                // 緩存操作條件不匹配,則寫入 excluded
                if (!context.isConditionPassing(CacheOperationExpressionEvaluator.RESULT_UNAVAILABLE)) {
                    excluded.add(context);
                }
            }
            catch (final VariableNotAvailableException ex) {
            }
        }
        // 檢查所有put是否已按條件排除
        return cachePutContexts.size() != excluded.size();
    }

    private void processCacheEvicts(
            Collection<CacheOperationContext> contexts, boolean beforeInvocation, @Nullable Object result) {
        for (final CacheOperationContext context : contexts) {
            final CacheEvictOperation operation = (CacheEvictOperation) context.metadata.operation;
            // 滿足緩存清除條件,則執行緩存清除
            if (beforeInvocation == operation.isBeforeInvocation() && isConditionPassing(context, result)) {
                performCacheEvict(context, operation, result);
            }
        }
    }

    private void performCacheEvict(
            CacheOperationContext context, CacheEvictOperation operation, @Nullable Object result) {
        Object key = null;
        for (final Cache cache : context.getCaches()) {
            // 1)是否清緩存中的所有條目,默認爲 false
            if (operation.isCacheWide()) {
                logInvalidating(context, operation, null);
                // 清除緩存中的所有條目
                doClear(cache);
            }
            else {
                if (key == null) {
                    // 計算緩存鍵
                    key = generateKey(context, result);
                }
                logInvalidating(context, operation, key);
                // 清除指定鍵關聯的條目
                doEvict(cache, key);
            }
        }
    }

    private void logInvalidating(CacheOperationContext context, CacheEvictOperation operation, @Nullable Object key) {
        if (logger.isTraceEnabled()) {
            logger.trace("Invalidating " + (key != null ? "cache key [" + key + "]" : "entire cache") +
                    " for operation " + operation + " on method " + context.metadata.method);
        }
    }

    @Nullable
    private Cache.ValueWrapper findCachedItem(Collection<CacheOperationContext> contexts) {
        final Object result = CacheOperationExpressionEvaluator.NO_RESULT;
        for (final CacheOperationContext context : contexts) {
            // 匹配緩存操作條件
            if (isConditionPassing(context, result)) {
                final Object key = generateKey(context, result);
                // 從緩存中查找值
                final 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;
    }

    private void collectPutRequests(Collection<CacheOperationContext> contexts,
            @Nullable Object result, Collection<CachePutRequest> putRequests) {
        for (final CacheOperationContext context : contexts) {
            if (isConditionPassing(context, result)) {
                final Object key = generateKey(context, result);
                // 添加緩存寫入請求
                putRequests.add(new CachePutRequest(context, key));
            }
        }
    }

    @Nullable
    private Cache.ValueWrapper findInCaches(CacheOperationContext context, Object key) {
        // 讀取所有關聯的緩存實例
        for (final Cache cache : context.getCaches()) {
            /**
             *  基於緩存鍵讀取值,如果找到則返回【
             *  可引入本地緩存+Redis緩存模式,本地緩存優先讀取】
             */
            final 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;
    }

    /**
     *  緩存操作條件是否匹配
     */
    private boolean isConditionPassing(CacheOperationContext context, @Nullable Object result) {
        final boolean passing = context.isConditionPassing(result);
        if (!passing && logger.isTraceEnabled()) {
            logger.trace("Cache condition failed on method " + context.metadata.method +
                    " for operation " + context.metadata.operation);
        }
        return passing;
    }

    /**
     *  計算緩存鍵
     */
    private Object generateKey(CacheOperationContext context, @Nullable Object result) {
        final Object key = context.generateKey(result);
        if (key == null) {
            throw new IllegalArgumentException("Null key returned for cache operation (maybe you are " +
                    "using named params on classes without debug info?) " + context.metadata.operation);
        }
        if (logger.isTraceEnabled()) {
            logger.trace("Computed cache key '" + key + "' for operation " + context.metadata.operation);
        }
        return key;
    }

    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) {
            contexts = new LinkedMultiValueMap<>(operations.size());
            for (final CacheOperation op : operations) {
                // 寫入映射
                contexts.add(op.getClass(), getOperationContext(op, method, args, target, targetClass));
            }
            // 寫入同步執行標識
            sync = determineSyncFlag(method);
        }

        /**
         *  讀取指定操作的 CacheOperationContext 集合
         */
        public Collection<CacheOperationContext> get(Class<? extends CacheOperation> operationClass) {
            final Collection<CacheOperationContext> result = contexts.get(operationClass);
            return result != null ? result : Collections.emptyList();
        }

        public boolean isSynchronized() {
            return sync;
        }

        private boolean determineSyncFlag(Method method) {
            // 1)無 @Cacheable 操作,sync 爲 false
            final List<CacheOperationContext> cacheOperationContexts = contexts.get(CacheableOperation.class);
            if (cacheOperationContexts == null) {  // no @Cacheable operation at all
                return false;
            }
            boolean syncEnabled = false;
            // 2)至少存在一個 @Cacheable 操作的 sync 標識位爲 true,則 sync 爲 true
            for (final CacheOperationContext cacheOperationContext : cacheOperationContexts) {
                if (((CacheableOperation) cacheOperationContext.getOperation()).isSync()) {
                    syncEnabled = true;
                    break;
                }
            }
            /**
             *  3)如果 sync 爲 true
             *  不能指定多個緩存操作
             *  Cacheable 操作不能關聯多個緩存
             *  不能指定 unless 條件
             */
            if (syncEnabled) {
                if (contexts.size() > 1) {
                    throw new IllegalStateException(
                            "@Cacheable(sync=true) cannot be combined with other cache operations on '" + method + "'");
                }
                if (cacheOperationContexts.size() > 1) {
                    throw new IllegalStateException(
                            "Only one @Cacheable(sync=true) entry is allowed on '" + method + "'");
                }
                final CacheOperationContext cacheOperationContext = cacheOperationContexts.iterator().next();
                final CacheableOperation operation = (CacheableOperation) cacheOperationContext.getOperation();
                if (cacheOperationContext.getCaches().size() > 1) {
                    throw new IllegalStateException(
                            "@Cacheable(sync=true) only allows a single cache on '" + operation + "'");
                }
                if (StringUtils.hasText(operation.getUnless())) {
                    throw new IllegalStateException(
                            "@Cacheable(sync=true) does not support unless attribute on '" + operation + "'");
                }
                return true;
            }
            return false;
        }
    }


    /**
     *  緩存操作的元數據
     */
    protected static class CacheOperationMetadata {
        private final CacheOperation operation;
        private final Method method;
        private final Class<?> targetClass;
        private final Method targetMethod;
        /**
         *  封裝了註解元素和目標類型的 AnnotatedElementKey
         */
        private final AnnotatedElementKey methodKey;
        private final KeyGenerator keyGenerator;
        private final CacheResolver cacheResolver;

        public CacheOperationMetadata(CacheOperation operation, Method method, Class<?> targetClass,
                KeyGenerator keyGenerator, CacheResolver cacheResolver) {
            this.operation = operation;
            this.method = BridgeMethodResolver.findBridgedMethod(method);
            this.targetClass = targetClass;
            targetMethod = !Proxy.isProxyClass(targetClass) ?
                    AopUtils.getMostSpecificMethod(method, targetClass) : this.method;
                    methodKey = new AnnotatedElementKey(targetMethod, targetClass);
                    this.keyGenerator = keyGenerator;
                    this.cacheResolver = cacheResolver;
        }
    }


    /**
     *  緩存操作上下文
     */
    protected class CacheOperationContext implements CacheOperationInvocationContext<CacheOperation> {
        private final CacheOperationMetadata metadata;
        private final Object[] args;
        private final Object target;
        private final Collection<? extends Cache> caches;
        private final Collection<String> cacheNames;
        @Nullable
        private Boolean conditionPassing;

        public CacheOperationContext(CacheOperationMetadata metadata, Object[] args, Object target) {
            this.metadata = metadata;
            this.args = extractArgs(metadata.method, args);
            this.target = target;
            caches = CacheAspectSupport.this.getCaches(this, metadata.cacheResolver);
            cacheNames = createCacheNames(caches);
        }

        @Override
        public CacheOperation getOperation() {
            return metadata.operation;
        }

        @Override
        public Object getTarget() {
            return target;
        }

        @Override
        public Method getMethod() {
            return metadata.method;
        }

        @Override
        public Object[] getArgs() {
            return args;
        }

        private Object[] extractArgs(Method method, Object[] args) {
            if (!method.isVarArgs()) {
                return args;
            }
            final Object[] varArgs = ObjectUtils.toObjectArray(args[args.length - 1]);
            final Object[] combinedArgs = new Object[args.length - 1 + varArgs.length];
            System.arraycopy(args, 0, combinedArgs, 0, args.length - 1);
            System.arraycopy(varArgs, 0, combinedArgs, args.length - 1, varArgs.length);
            return combinedArgs;
        }

        protected boolean isConditionPassing(@Nullable Object result) {
            if (conditionPassing == null) {
                // 1)註解的緩存條件不爲空
                if (StringUtils.hasText(metadata.operation.getCondition())) {
                    // 創建計算上下文
                    final EvaluationContext evaluationContext = createEvaluationContext(result);
                    // 基於 CacheOperationExpressionEvaluator 計算目標條件
                    conditionPassing = evaluator.condition(metadata.operation.getCondition(),
                            metadata.methodKey, evaluationContext);
                }
                else {
                    // 2)未指定條件默認匹配
                    conditionPassing = true;
                }
            }
            return conditionPassing;
        }

        /**
         *  unless 條件未指定或爲 false 時,才允許將結果加入到緩存中
         */
        protected boolean canPutToCache(@Nullable Object value) {
            String unless = "";
            // 1)從 CacheableOperation 讀取 unless 條件
            if (metadata.operation instanceof CacheableOperation) {
                unless = ((CacheableOperation) metadata.operation).getUnless();
            }
            // 2)從 CachePutOperation 讀取 unless 條件
            else if (metadata.operation instanceof CachePutOperation) {
                unless = ((CachePutOperation) metadata.operation).getUnless();
            }
            // 如果 unless 條件不爲空,則計算其值
            if (StringUtils.hasText(unless)) {
                final EvaluationContext evaluationContext = createEvaluationContext(value);
                return !evaluator.unless(unless, metadata.methodKey, evaluationContext);
            }
            // 未指定,則默認將結果加入緩存中
            return true;
        }

        /**
         * Compute the key for the given caching operation.
         */
        @Nullable
        protected Object generateKey(@Nullable Object result) {
            // 1)基於指定的 SpEL 表達式解析緩存鍵
            if (StringUtils.hasText(metadata.operation.getKey())) {
                final EvaluationContext evaluationContext = createEvaluationContext(result);
                return evaluator.key(metadata.operation.getKey(), metadata.methodKey, evaluationContext);
            }

            // 2)基於鍵生成器生成緩存鍵
            return metadata.keyGenerator.generate(target, metadata.method, args);
        }

        private EvaluationContext createEvaluationContext(@Nullable Object result) {
            return evaluator.createEvaluationContext(caches, metadata.method, args,
                    target, metadata.targetClass, metadata.targetMethod, result, beanFactory);
        }

        protected Collection<? extends Cache> getCaches() {
            return caches;
        }

        protected Collection<String> getCacheNames() {
            return cacheNames;
        }

        private Collection<String> createCacheNames(Collection<? extends Cache> caches) {
            final Collection<String> names = new ArrayList<>();
            for (final Cache cache : caches) {
                names.add(cache.getName());
            }
            return names;
        }
    }


    private class CachePutRequest {
        /**
         *  緩存操作上下文
         */
        private final CacheOperationContext context;
        /**
         *  緩存鍵
         */
        private final Object key;

        public CachePutRequest(CacheOperationContext context, Object key) {
            this.context = context;
            this.key = key;
        }

        public void apply(@Nullable Object result) {
            // 方法執行結果是否需要加入緩存中
            if (context.canPutToCache(result)) {
                // 將結果加入相關的緩存中
                for (final Cache cache : context.getCaches()) {
                    doPut(cache, key, result);
                }
            }
        }
    }

    private static final class CacheOperationCacheKey implements Comparable<CacheOperationCacheKey> {
        /**
         *  緩存操作
         */
        private final CacheOperation cacheOperation;
        /**
         *  註解元素
         */
        private final AnnotatedElementKey methodCacheKey;

        private CacheOperationCacheKey(CacheOperation cacheOperation, Method method, Class<?> targetClass) {
            this.cacheOperation = cacheOperation;
            methodCacheKey = new AnnotatedElementKey(method, targetClass);
        }

        @Override
        public boolean equals(Object other) {
            if (this == other) {
                return true;
            }
            if (!(other instanceof CacheOperationCacheKey)) {
                return false;
            }
            final CacheOperationCacheKey otherKey = (CacheOperationCacheKey) other;
            return cacheOperation.equals(otherKey.cacheOperation) &&
                    methodCacheKey.equals(otherKey.methodCacheKey);
        }

        @Override
        public int hashCode() {
            return cacheOperation.hashCode() * 31 + methodCacheKey.hashCode();
        }

        @Override
        public String toString() {
            return cacheOperation + " on " + methodCacheKey;
        }

        @Override
        public int compareTo(CacheOperationCacheKey other) {
            int result = cacheOperation.getName().compareTo(other.cacheOperation.getName());
            if (result == 0) {
                result = methodCacheKey.compareTo(other.methodCacheKey);
            }
            return result;
        }
    }

}

/**
 *  聲明式緩存管理 MethodInterceptor
 */
@SuppressWarnings("serial")
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);
            }
        };

        try {
            // 執行核心操作
            return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments());
        }
        catch (CacheOperationInvoker.ThrowableWrapper th) {
            throw th.getOriginal();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章