spring cache注解驱动

fxz大约 92 分钟

spring cache注解驱动

概述

快速使用open in new window

官方文档open in new window

省流

利用spring aop。

拦截逻辑:类或者方法上有相应注解。

增强逻辑:解析注解元信息执行相应操作。

核心注解

@EnableCaching

作用:开启Spring注解驱动的Cache支持。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {

    /**
     * 指示是否要创建基于子类的 (CGLIB) 代理,而不是
     * 到基于标准 Java 接口的代理。默认值为 {@code false}。
     */
    boolean proxyTargetClass() default false;

    /**
     * 如何应用缓存建议(Advised)。
     */
    AdviceMode mode() default AdviceMode.PROXY;

    /**
     * 缓存顾问(Advisor)的执行顺序
     * 当在特定连接点应用多个建议(Advised)时。
     * <p>默认值为 {@link Ordered#LOWEST_PRECEDENCE}。
     */
    int order() default Ordered.LOWEST_PRECEDENCE;

}

@CacheConfig

作用:类级别的默认缓存配置。

/**
 * {@code @CacheConfig} 提供了一种共享公共缓存相关机制
 * class级别的设置。
 *
 * <p>当这个注解存在于给定的类上时,它提供了一个集合
 * 该类中定义的任何缓存操作的默认设置。
 *
 * @author Stephane Nicoll
 * @author Sam Brannen
 * @since 4.1
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheConfig {

    /**
     * 定义的缓存操作要考虑的默认缓存的名称
     */
    String[] cacheNames() default {};

    /**
     * 默认 {@link org.springframework.cache.interceptor.KeyGenerator} 的 bean 名称
     */
    String keyGenerator() default "";

    /**
     * 自定义{@link org.springframework.cache.CacheManager}的bean名称,用于
     * 创建一个默认的{@link org.springframework.cache.interceptor.CacheResolver} 如果没有设置。
     * @see org.springframework.cache.interceptor.SimpleCacheResolver
     */
    String cacheManager() default "";

    /**
     * 要使用的自定义 {@link org.springframework.cache.interceptor.CacheResolver} 的 bean 名称。
     */
    String cacheResolver() default "";

}

@Cacheable

作用:缓存调用方法的结果,仅在不存在相应缓存时执行目标方法。

/**
 * 缓存调用方法的结果。
 *
 * <p>每次调用建议(Advised)的方法时,都会应用缓存行为,
 * 检查是否已经为给定的参数调用过该方法。
 * 默认值只是使用方法参数来计算密钥,但
 * SpEL 表达式可以通过 {@link #key} 属性或自定义
 * {@link org.springframework.cache.interceptor.KeyGenerator} 实现可以
 * 替换默认的(参见 {@link #keyGenerator})。
 *
 * <p>如果在计算键的缓存中找不到值,则目标方法
 * 将被调用,返回的值将存储在关联的缓存中。
 * 请注意,{@link java.util.Optional} 返回类型是自动解包的。
 * 如果 {@code Optional} 值为 {@linkplain java.util.Optional#isPresent()
 * present},它将存储在关联的缓存中。如果 {@code Optional}
 * value 不存在,{@code null} 将存储在关联的缓存中。
 *
 * <p>此注解可用作<em>元注</em>解来创建自定义
 * 带有属性覆盖的<em>组合注释</em>。
 *
 * @author Costin Leau
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @author Sam Brannen
 * @since 3.1
 * @see CacheConfig
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {

    /**
     * Alias for {@link #cacheNames}.
     */
    @AliasFor("cacheNames")
    String[] value() default {};

    /**
     * 存储方法调用结果的缓存的名称。
     * <p>名称可用于确定目标缓存(或多个缓存),匹配
     * 特定 Bean 定义的限定符值或 Bean 名称。
     * @since 4.2
     * @see #value
     * @see CacheConfig#cacheNames
     */
    @AliasFor("value")
    String[] cacheNames() default {};

    /**
     * Spring 表达式语言 (SpEL) 表达式,用于动态计算密钥。
     * <p>默认值为 {@code “”},表示所有方法参数都被视为一个键,
     * 除非已配置自定义 {@link #keyGenerator}。
     * <p>SpEL 表达式根据提供
     * 以下元数据:
     * <ul>
     * {<li>@code #root.method}{@code #root.target}{@code #root.caches}
     * 对 {@link java.lang.reflect.Method method}、目标对象和
     * 分别受影响的缓存。</li>
     * <li>方法名称 ({@code #root.methodName}) 和目标类的快捷方式
     * ({@code #root.targetClass}) 也可用。
     * <li>方法参数可以通过索引访问。例如,第二个参数
     * 可以通过 {@code #root.args[1]}{@code #p1}{@code #a1} 访问。参数
     * 如果该信息可用,也可以按名称访问。</li>
     * </ul>
     */
    String key() default "";

    /**
     * 自定义 {@link org.springframework.cache.interceptor.KeyGenerator} 的 Bean 名称
     * 使用。
     * <p>{@link #key} 属性互斥。
     * @see CacheConfig#keyGenerator
     */
    String keyGenerator() default "";

    /**
     * 自定义{@link org.springframework.cache.CacheManager}的bean名称,用于
     * 创建一个默认的{@link org.springframework.cache.interceptor.CacheResolver} 如果没有设置。
     * <p>{@link #cacheResolver} 属性互斥。
     * @see org.springframework.cache.interceptor.SimpleCacheResolver
     * @see CacheConfig#cacheManager
     */
    String cacheManager() default "";

    /**
     * 自定义 {@link org.springframework.cache.interceptor.CacheResolver} 的 Bean 名称
     * 使用。
     * @see CacheConfig#cacheResolver
     */
    String cacheResolver() default "";

    /**
     * 缓存是有条件的。
     * <p>默认值为 {@code “”},表示始终缓存方法结果。
     * <p>SpEL 表达式根据提供
     * 以下元数据:
     * <ul>
     * {<li>@code #root.method}{@code #root.target}{@code #root.caches}
     * 对 {@link java.lang.reflect.Method method}、目标对象和
     * 分别受影响的缓存。</li>
     * <li>方法名称 ({@code #root.methodName}) 和目标类的快捷方式
     * ({@code #root.targetClass}) 也可用。
     * <li>方法参数可以通过索引访问。例如,第二个参数
     * 可以通过 {@code #root.args[1]}{@code #p1}{@code #a1} 访问。参数
     * 如果该信息可用,也可以按名称访问。</li>
     * </ul>
     */
    String condition() default "";

    /**
     * 表达式用于否决方法缓存。
     * <p>{@link #condition} 不同,此表达式在方法之后计算
     * 已被调用,因此可以引用 {@code result}。
     * <p>默认值为 {@code “”},表示缓存永远不会被否决。
     * <p>SpEL 表达式根据提供
     * 以下元数据:
     * <ul>
     * <li>{@code #result} 表示对方法调用结果的引用。为
     * 支持的包装器如 {@code Optional}{@code #result} 是指实际的
     * 对象,而不是包装器</li>
     * {<li>@code #root.method}{@code #root.target}{@code #root.caches}
     * 对 {@link java.lang.reflect.Method method}、目标对象和
     * 分别受影响的缓存。</li>
     * <li>方法名称 ({@code #root.methodName}) 和目标类的快捷方式
     * ({@code #root.targetClass}) 也可用。
     * <li>方法参数可以通过索引访问。例如,第二个参数
     * 可以通过 {@code #root.args[1]}{@code #p1}{@code #a1} 访问。参数
     * 如果该信息可用,也可以按名称访问。</li>
     * </ul>
     * @since 3.2
     */
    String unless() default "";

    /**
     * 如果多个线程
     * 尝试加载同一键的值。同步导致
     * 有几个限制:
     * <ol>
     * <li>不支持 {@link #unless()}</li>
     * <li>只能指定一个缓存</li>
     * <li>不能组合其他与缓存相关的操作</li>
     * </ol>
     * @since 4.3
     * @see org.springframework.cache.Cache#get(Object, Callable)
     */
    boolean sync() default false;

}

@CachePut

作用:缓存方法返回值。

/**
 * 方法(或类上的所有方法)触发
 * {@link org.springframework.cache.Cache#put(Object, Object) cache put} 操作。
 *
 * <p>{@link Cacheable @Cacheable} 注解相比,此注解
 * 不会导致跳过建议(Advised)的方法。相反,它总是会导致
 * 方法,其结果将存储在关联的缓存中,如果
 * {@link #condition()}{@link #unless()} 表达式相应匹配。注意
 * Java8 的 {@code Optional} 返回类型被自动处理,其
 * 内容存储在缓存中(如果存在)。
 *
 * <p>此注解可用作<em>元注</em>解来创建自定义
 * 带有属性覆盖的<em>组合注释</em>。
 *
 * @author Costin Leau
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @author Sam Brannen
 * @since 3.1
 * @see CacheConfig
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CachePut {

    /**
     * Alias for {@link #cacheNames}.
     */
    @AliasFor("cacheNames")
    String[] value() default {};

    /**
     * 用于缓存放置操作的缓存的名称。
     * <p>名称可用于确定目标缓存(或多个缓存),匹配
     * 特定 Bean 定义的限定符值或 Bean 名称。
     * @since 4.2
     * @see #value
     * @see CacheConfig#cacheNames
     */
    @AliasFor("value")
    String[] cacheNames() default {};

    /**
     * Spring 表达式语言 (SpEL) 表达式,用于动态计算密钥。
     * <p>默认值为 {@code “”},表示所有方法参数都被视为一个键,
     * 除非设置了自定义 {@link #keyGenerator}。
     * <p>SpEL 表达式根据提供
     * 以下元数据:
     * <ul>
     * <li>{@code #result} 表示对方法调用结果的引用。为
     * 支持的包装器如 {@code Optional}{@code #result} 是指实际的
     * 对象,而不是包装器</li>
     * {<li>@code #root.method}{@code #root.target}{@code #root.caches}
     * 对 {@link java.lang.reflect.Method method}、目标对象和
     * 分别受影响的缓存。</li>
     * <li>方法名称 ({@code #root.methodName}) 和目标类的快捷方式
     * ({@code #root.targetClass}) 也可用。
     * <li>方法参数可以通过索引访问。例如,第二个参数
     * 可以通过 {@code #root.args[1]}{@code #p1}{@code #a1} 访问。参数
     * 如果该信息可用,也可以按名称访问。</li>
     * </ul>
     */
    String key() default "";

    /**
     * 自定义 {@link org.springframework.cache.interceptor.KeyGenerator} 的 Bean 名称
     * 使用。
     * <p>{@link #key} 属性互斥。
     * @see CacheConfig#keyGenerator
     */
    String keyGenerator() default "";

    /**
     * 自定义{@link org.springframework.cache.CacheManager}的bean名称,用于
     * 创建一个默认的{@link org.springframework.cache.interceptor.CacheResolver} 如果没有
     * 已设置。
     * <p>{@link #cacheResolver} 属性互斥。
     * @see org.springframework.cache.interceptor.SimpleCacheResolver
     * @see CacheConfig#cacheManager
     */
    String cacheManager() default "";

    /**
     * 自定义 {@link org.springframework.cache.interceptor.CacheResolver} 的 Bean 名称
     * 使用。
     * @see CacheConfig#cacheResolver
     */
    String cacheResolver() default "";

    /**
     * 用于创建缓存的 Spring 表达式语言 (SpEL) 表达式
     * 把操作有条件。
     * <p>此表达式在调用方法后计算,因为
     * PUT 操作的性质,因此可以参考 {@code result}。
     * <p>默认值为 {@code “”},表示始终缓存方法结果。
     * <p>SpEL 表达式根据提供
     * 以下元数据:
     * <ul>
     * <li>{@code #result} 表示对方法调用结果的引用。为
     * 支持的包装器如 {@code Optional}{@code #result} 是指实际的
     * 对象,而不是包装器</li>
     * {<li>@code #root.method}{@code #root.target}{@code #root.caches}
     * 对 {@link java.lang.reflect.Method method}、目标对象和
     * 分别受影响的缓存。</li>
     * <li>方法名称 ({@code #root.methodName}) 和目标类的快捷方式
     * ({@code #root.targetClass}) 也可用。
     * <li>方法参数可以通过索引访问。例如,第二个参数
     * 可以通过 {@code #root.args[1]}{@code #p1}{@code #a1} 访问。参数
     * 如果该信息可用,也可以按名称访问。</li>
     * </ul>
     */
    String condition() default "";

    /**
     * Spring 表达式语言 (SpEL) 表达式用于否决缓存放置操作。
     * <p>默认值为 {@code “”},表示缓存永远不会被否决。
     * <p>SpEL 表达式根据提供
     * 以下元数据:
     * <ul>
     * <li>{@code #result} 表示对方法调用结果的引用。为
     * 支持的包装器如 {@code Optional}{@code #result} 是指实际的
     * 对象,而不是包装器</li>
     * {<li>@code #root.method}{@code #root.target}{@code #root.caches}
     * 对 {@link java.lang.reflect.Method method}、目标对象和
     * 分别受影响的缓存。</li>
     * <li>方法名称 ({@code #root.methodName}) 和目标类的快捷方式
     * ({@code #root.targetClass}) 也可用。
     * <li>方法参数可以通过索引访问。例如,第二个参数
     * 可以通过 {@code #root.args[1]}{@code #p1}{@code #a1} 访问。参数
     * 如果该信息可用,也可以按名称访问。</li>
     * </ul>
     * @since 3.2
     */
    String unless() default "";

}

CacheEvict

作用:清除缓存。

/**
 * 指示一个方法(或一个类上的所有方法)触发
 * {@link org.springframework.cache.Cache#evict(Object) cache evict} 操作。
 *
 * @author Costin Leau
 * @author Stephane Nicoll
 * @author Sam Brannen
 * @since 3.1
 * @see CacheConfig
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheEvict {

    @AliasFor("cacheNames")
    String[] value() default {};

    @AliasFor("value")
    String[] cacheNames() default {};
  
    String key() default "";

    String keyGenerator() default "";

    String cacheManager() default "";

    String cacheResolver() default "";

    String condition() default "";

    /**
     * 是否删除缓存中的所有条目。
     * <p>默认情况下,仅删除关联键下的值。
     * <p>请注意,将此参数设置为 {@code true} 并指定
     * {@link #key} 是不允许的。
     */
    boolean allEntries() default false;

    /**
     * 是否应在调用方法之前进行逐出。
     * <p>将此属性设置为 {@code true},将导致逐出
     * 无论方法结果如何(即,它是否抛出
     * 例外与否)。
     * <p>默认为 {@code false},表示缓存逐出操作
     * 将在成功调用建议的方法<em></em>发生(即
     * 仅当调用未引发异常时)。
     */
    boolean beforeInvocation() default false;

}

@Caching

作用:组合多个上述注解(不同或相同类型)。

/**
 * 多个缓存批注(不同或相同类型)的组批注。
 *
 * <p>此注解可用作<em>元注</em>解来创建自定义
 * 带有属性覆盖的<em>组合注释</em>。
 *
 * @author Costin Leau
 * @author Chris Beams
 * @since 3.1
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Caching {

    Cacheable[] cacheable() default {};

    CachePut[] put() default {};

    CacheEvict[] evict() default {};

}

核心类

AnnotationCacheOperationSource

作用:解析方法或者类上缓存相关的注解。

/**
 * {@link CacheInterceptor} 使用的接口。实现知道如何获取
 * 缓存操作属性,无论是来自配置,还是元数据属性源级别,或其他地方。
 *
 * @author Costin Leau
 * @author Juergen Hoeller
 * @since 3.1
 */
public interface CacheOperationSource {

    /**
     * 确定给定类是否为缓存操作的候选项
     * 采用此 {@code CacheOperationSource} 的元数据格式。
     * <p>如果此方法返回 {@code false},则给定类上的方法
     * 不会因 {@link #getCacheOperations} 内省而被遍历。
     * 因此,返回 {@code false} 是对不受影响的优化
     * ,而 {@code true} 仅表示该类需要获取
     * 对给定类上的每个方法分别进行完全内省。
     * @param targetClass 要自省的类
     * @return {@code false} 如果已知该类没有缓存操作
     * 类或方法级别的元数据;{@code true} 否则。默认
     * 实现返回 {@code true},导致定期内省。
     * @since 5.2
     */
    default boolean isCandidateClass(Class<?> targetClass) {
       return true;
    }

    /**
     * 返回此方法的缓存操作集合,
     * 或 {@code null}(如果该方法不包含<em>可缓存</em>的注释)。
     * @param method 内省的方法
     * @param targetClass 目标类(可能是 {@code null},在这种情况下
     * 必须使用方法的声明类)
     * @return 此方法的所有缓存操作,如果未找到,则为 {@code null}
     */
    @Nullable
    Collection<CacheOperation> getCacheOperations(Method method, @Nullable Class<?> targetClass);

}
/**
 * 缓存属性的 {@link CacheOperation} 的抽象实现
 * 对于方法和实施回退策略:
 * 1.特定目标方法;
 * 2.目标类;
 * 3.申报方式;
 * 4. 声明类/接口。
 *
 * <p>默认使用目标类的缓存属性,如果没有
 * 与目标方法相关联。与 关联的任何缓存属性
 * Target 方法完全覆盖类缓存属性。
 * 如果在目标类上找不到,则调用方法的接口
 * 已被调用(如果是 JDK 代理)将被检查。
 *
 * <p>此实现在属性第一个之后按方法缓存属性
 * 使用。如果希望允许动态更改可缓存
 * 属性(这不太可能),缓存可以被配置。
 *
 * @author Costin Leau
 * @author Juergen Hoeller
 * @since 3.1
 */
public abstract class AbstractFallbackCacheOperationSource implements CacheOperationSource {

	private static final Collection<CacheOperation> NULL_CACHING_ATTRIBUTE = Collections.emptyList();
	protected final Log logger = LogFactory.getLog(getClass());

	/**
	 * CacheOperations 的缓存,按特定目标类上的方法进行键控。
	 * <p>由于此基类未标记为 Serializable,因此将重新创建缓存
	 * 序列化后 - 前提是具体子类是 Serializable。
	 */
	private final Map<Object, Collection<CacheOperation>> attributeCache = new ConcurrentHashMap<>(1024);


	/**
	 * 确定此方法调用的缓存属性。
	 * <p>如果未找到 method 属性,则默认为类的 caching 属性。
	 *
	 * @param method      当前调用的方法(从不 {@code null})
	 * @param targetClass 此调用的目标类(可能是 {@code null})
	 * @return {@link CacheOperation} 表示此方法,如果该方法为 {@code null},则为 { null}
	 * 不可缓存
	 */
	@Override
	@Nullable
	public Collection<CacheOperation> getCacheOperations(Method method, @Nullable Class<?> targetClass) {
		// Object的方法 就返回null
		if (method.getDeclaringClass() == Object.class) {
			return null;
		}

		Object cacheKey = getCacheKey(method, targetClass);
		Collection<CacheOperation> cached = this.attributeCache.get(cacheKey);

		// 有缓存
		if (cached != null) {
			return (cached != NULL_CACHING_ATTRIBUTE ? cached : null);
		} else {
			/**
			 * 先找方法,找不到,再从类上找 @Caching、@Cacheable、@CacheEvict、@CachePut
			 * */
			Collection<CacheOperation> cacheOps = computeCacheOperations(method, targetClass);
			if (cacheOps != null) {
				if (logger.isTraceEnabled()) {
					logger.trace("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheOps);
				}
				// 缓存起来
				this.attributeCache.put(cacheKey, cacheOps);
			} else {
				// 缓存空值
				this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
			}
			return cacheOps;
		}
	}

	/**
	 * Determine a cache key for the given method and target class.
	 * <p>Must not produce same key for overloaded methods.
	 * Must produce same key for different instances of the same method.
	 *
	 * @param method      the method (never {@code null})
	 * @param targetClass the target class (may be {@code null})
	 * @return the cache key (never {@code null})
	 */
	protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) {
		return new MethodClassKey(method, targetClass);
	}

	@Nullable
	private Collection<CacheOperation> computeCacheOperations(Method method, @Nullable Class<?> targetClass) {
		// 方法不是public 就返回null
		// Don't allow no-public methods as required.
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		// 如果 targetClass 是代理类,就返回被代理的方法
		// The method may be on an interface, but we need attributes from the target class.
		// If the target class is null, the method will be unchanged.
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

		// 被代理类的方法是否有
		// First try is the method in the target class.
		Collection<CacheOperation> opDef = findCacheOperations(specificMethod);
		if (opDef != null) {
			return opDef;
		}

		// 被代理类是否有
		// Second try is the caching operation on the target class.
		opDef = findCacheOperations(specificMethod.getDeclaringClass());
		if (opDef != null && ClassUtils.isUserLevelMethod(method)) {
			return opDef;
		}

		// 不相等,说明有代理类和代理方法
		if (specificMethod != method) {
			// 代理类的方法是否有
			// Fallback is to look at the original method.
			opDef = findCacheOperations(method);
			if (opDef != null) {
				return opDef;
			}
			// 代理类是否有
			// Last fallback is the class of the original method.
			opDef = findCacheOperations(method.getDeclaringClass());
			if (opDef != null && ClassUtils.isUserLevelMethod(method)) {
				return opDef;
			}
		}

		return null;
	}


	/**
	 * 子类需要实现这一点才能返回给定的class,如果有的话。
	 *
	 * @param clazz 类以检索 的属性
	 * @return 与此类关联的所有缓存属性,如果没有,则为 {@code null}
	 */
	@Nullable
	protected abstract Collection<CacheOperation> findCacheOperations(Class<?> clazz);

	/**
	 * 子类需要实现这一点才能返回给定方法(如果有)。
	 *
	 * @param method 检索属性的方法
	 * @return 与此方法关联的所有缓存属性,如果没有,则为 {@code null}
	 */
	@Nullable
	protected abstract Collection<CacheOperation> findCacheOperations(Method method);

	/**
	 * 是否应该只允许公共方法具有缓存语义?
	 * <p>默认实现返回 {@code false}。
	 */
	protected boolean allowPublicMethodsOnly() {
		return false;
	}

}

/**
 * {@link org.springframework.cache.interceptor.CacheOperationSource 的实现
 * CacheOperationSource} 接口,用于处理以注释格式缓存元数据。
 *
 * <p>此类读取 Spring 的 {@link Cacheable}{@link CachePut}{@link CacheEvict}
 * 注解,并将相应的缓存操作定义暴露给 Spring 的缓存
 * 基础设施。此类还可以用作自定义项的基类
 * {@code CacheOperationSource}。
 *
 * @author Costin Leau
 * @author Juergen Hoeller
 * @author Stephane Nicoll
 * @since 3.1
 */
@SuppressWarnings("serial")
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implements Serializable {

    private final boolean publicMethodsOnly;

    private final Set<CacheAnnotationParser> annotationParsers;

    /**
     * 依赖于CacheAnnotationParser 默认有SpringCacheAnnotationParser的实现
     * @param targetClass 要自省的类
     */
    @Override
    public boolean isCandidateClass(Class<?> targetClass) {
        for (CacheAnnotationParser parser : this.annotationParsers) {
            if (parser.isCandidateClass(targetClass)) {
                return true;
            }
        }
        return false;
    }

    @Override
    @Nullable
    protected Collection<CacheOperation> findCacheOperations(Class<?> clazz) {
        return determineCacheOperations(parser -> parser.parseCacheAnnotations(clazz));
    }

    @Override
    @Nullable
    protected Collection<CacheOperation> findCacheOperations(Method method) {
        return determineCacheOperations(parser -> parser.parseCacheAnnotations(method));
    }

    /**
     * 确定给定 {@link CacheOperationProvider} 的缓存操作。
     * <p>此实现委托给已配置
     * {@link CacheAnnotationParser CacheAnnotationParsers}
     * 用于将已知注解解析到 Spring 的元数据属性类中。
     * <p>可以覆盖以支持带有缓存元数据的自定义注释。
     * @param provider 要使用的缓存操作提供程序
     * @return 配置的缓存操作,如果没有找到,则 {@code null}
     */
    @Nullable
    protected Collection<CacheOperation> determineCacheOperations(CacheOperationProvider provider) {
        // 类或者方法 解析出来的 CacheOperation
        Collection<CacheOperation> ops = null;
        // 默认就一个parser ---> SpringCacheAnnotationParser
        for (CacheAnnotationParser parser : this.annotationParsers) {
            /**
             * getCacheOperations 是执行这个
             *  {@link SpringCacheAnnotationParser#parseCacheAnnotations(Method)}
             *  {@link SpringCacheAnnotationParser#parseCacheAnnotations(Class)}
             *
             * 逻辑很简单,从方法或者类上 找 @Cacheable、@CacheEvict、@CachePut、@Caching 每个都会解析成 CacheOperation 对象,
             * 比如:
             *      - 方法:方法有匹配的注解、方法的接口方法有匹配的注解、父类方法有匹配的注解 已最小维度为准,返回的是方法上匹配的注解
             *      - 类:类有匹配的注解、类的父类有匹配的注解、类的接口有匹配的注解 已最小维度为准,返回的是类上匹配的注解
             * */
            Collection<CacheOperation> annOps = provider.getCacheOperations(parser);
            if (annOps != null) {
                if (ops == null) {
                    ops = annOps;
                } else {
                    // 汇总parser解析的值
                    Collection<CacheOperation> combined = new ArrayList<>(ops.size() + annOps.size());
                    combined.addAll(ops);
                    combined.addAll(annOps);
                    // 赋值
                    ops = combined;
                }
            }
        }
        return ops;
    }

    /**
     * By default, only public methods can be made cacheable.
     */
    @Override
    protected boolean allowPublicMethodsOnly() {
        return this.publicMethodsOnly;
    }

    /**
     * Callback interface providing {@link CacheOperation} instance(s) based on
     * a given {@link CacheAnnotationParser}.
     */
    @FunctionalInterface
    protected interface CacheOperationProvider {

        /**
         * Return the {@link CacheOperation} instance(s) provided by the specified parser.
         * @param parser the parser to use
         * @return the cache operations, or {@code null} if none found
         */
        @Nullable
        Collection<CacheOperation> getCacheOperations(CacheAnnotationParser parser);
    }

}

SpringCacheAnnotationParser

作用:缓存注解解析器。

public interface CacheAnnotationParser {

    default boolean isCandidateClass(Class<?> targetClass) {
       return true;
    }
  
    @Nullable
    Collection<CacheOperation> parseCacheAnnotations(Class<?> type);

    @Nullable
    Collection<CacheOperation> parseCacheAnnotations(Method method);

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


    @Override
    public boolean isCandidateClass(Class<?> targetClass) {
        return AnnotationUtils.isCandidateClass(targetClass, CACHE_OPERATION_ANNOTATIONS);
    }

    @Override
    @Nullable
    public Collection<CacheOperation> parseCacheAnnotations(Class<?> type) {
        // 这个很关键用来解析类上的 @CacheConfig
        DefaultCacheConfig defaultConfig = new DefaultCacheConfig(type);
        return parseCacheAnnotations(defaultConfig, type);
    }

    @Override
    @Nullable
    public Collection<CacheOperation> parseCacheAnnotations(Method method) {
        // 这个很关键用来解析类上的 @CacheConfig
        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;
    }

    @Nullable
    private Collection<CacheOperation> parseCacheAnnotations(
            DefaultCacheConfig cachingConfig, AnnotatedElement ae, boolean localOnly) {

        /**
         * 就是从 ae 上找到 @Cacheable、@CacheEvict、@CachePut、@Caching 这些注解
         * */
        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)));
        // @Caching 就是上面 三个的合并写法,所以这里会传入 ops ,解析 @Caching 其实还是按照三个注解解析 赛道 ops中
        anns.stream().filter(ann -> ann instanceof Caching).forEach(
                ann -> parseCachingAnnotation(ae, cachingConfig, (Caching) ann, ops));
        return ops;
    }

    private CacheableOperation parseCacheableAnnotation(
            AnnotatedElement ae, DefaultCacheConfig defaultConfig, Cacheable cacheable) {

        CacheableOperation.Builder builder = new CacheableOperation.Builder();

        // 这里是将方法上注解的值 做映射
        builder.setName(ae.toString());
        builder.setCacheNames(cacheable.cacheNames());
        builder.setCondition(cacheable.condition());
        builder.setUnless(cacheable.unless());
        builder.setKey(cacheable.key());
        builder.setKeyGenerator(cacheable.keyGenerator());
        builder.setCacheManager(cacheable.cacheManager());
        builder.setCacheResolver(cacheable.cacheResolver());
        builder.setSync(cacheable.sync());

        // 应用默认值,
        defaultConfig.applyDefault(builder);
        // 生成 CacheableOperation 实例
        CacheableOperation op = builder.build();
        // 验证
        validateCacheOperation(ae, op);

        return op;
    }

    private CacheEvictOperation parseEvictAnnotation(
            AnnotatedElement ae, DefaultCacheConfig defaultConfig, CacheEvict cacheEvict) {

        CacheEvictOperation.Builder builder = new CacheEvictOperation.Builder();

        builder.setName(ae.toString());
        builder.setCacheNames(cacheEvict.cacheNames());
        builder.setCondition(cacheEvict.condition());
        builder.setKey(cacheEvict.key());
        builder.setKeyGenerator(cacheEvict.keyGenerator());
        builder.setCacheManager(cacheEvict.cacheManager());
        builder.setCacheResolver(cacheEvict.cacheResolver());
        builder.setCacheWide(cacheEvict.allEntries());
        builder.setBeforeInvocation(cacheEvict.beforeInvocation());

        defaultConfig.applyDefault(builder);
        CacheEvictOperation op = builder.build();
        validateCacheOperation(ae, op);

        return op;
    }

    private CacheOperation parsePutAnnotation(
            AnnotatedElement ae, DefaultCacheConfig defaultConfig, CachePut cachePut) {

        CachePutOperation.Builder builder = new CachePutOperation.Builder();

        builder.setName(ae.toString());
        builder.setCacheNames(cachePut.cacheNames());
        builder.setCondition(cachePut.condition());
        builder.setUnless(cachePut.unless());
        builder.setKey(cachePut.key());
        builder.setKeyGenerator(cachePut.keyGenerator());
        builder.setCacheManager(cachePut.cacheManager());
        builder.setCacheResolver(cachePut.cacheResolver());

        defaultConfig.applyDefault(builder);
        CachePutOperation op = builder.build();
        validateCacheOperation(ae, op);

        return op;
    }

    private void parseCachingAnnotation(
            AnnotatedElement ae, DefaultCacheConfig defaultConfig, Caching caching, Collection<CacheOperation> ops) {

        Cacheable[] cacheables = caching.cacheable();
        for (Cacheable cacheable : cacheables) {
            ops.add(parseCacheableAnnotation(ae, defaultConfig, cacheable));
        }
        CacheEvict[] cacheEvicts = caching.evict();
        for (CacheEvict cacheEvict : cacheEvicts) {
            ops.add(parseEvictAnnotation(ae, defaultConfig, cacheEvict));
        }
        CachePut[] cachePuts = caching.put();
        for (CachePut cachePut : cachePuts) {
            ops.add(parsePutAnnotation(ae, defaultConfig, cachePut));
        }
    }

    private void validateCacheOperation(AnnotatedElement ae, CacheOperation operation) {
        if (StringUtils.hasText(operation.getKey()) && StringUtils.hasText(operation.getKeyGenerator())) {
            throw new IllegalStateException("Invalid cache annotation configuration on '" +
                                            ae.toString()
                                            + "'. Both 'key' and 'keyGenerator' attributes have been set. " +
                                            "These attributes are mutually exclusive: either set the SpEL expression used to"
                                            +
                                            "compute the key at runtime or set the name of the KeyGenerator bean to use.");
        }
        if (StringUtils.hasText(operation.getCacheManager()) && StringUtils.hasText(operation.getCacheResolver())) {
            throw new IllegalStateException("Invalid cache annotation configuration on '" +
                                            ae.toString()
                                            + "'. Both 'cacheManager' and 'cacheResolver' attributes have been set. " +
                                            "These attributes are mutually exclusive: the cache manager is used to configure a"
                                            +
                                            "default cache resolver if none is set. If a cache resolver is set, the cache manager"
                                            +
                                            "won't be used.");
        }
    }

    /**
     * 为给定的一组缓存操作提供默认设置。
     */
    private static class DefaultCacheConfig {

        private final Class<?> target;

        @Nullable
        private String[] cacheNames;

        @Nullable
        private String keyGenerator;

        @Nullable
        private String cacheManager;

        @Nullable
        private String cacheResolver;

        private boolean initialized = false;

        public DefaultCacheConfig(Class<?> target) {
            this.target = target;
        }

        /**
         * 将默认值应用于指定的{@link CacheOperation.Builder}。
         * @param builder要更新的操作生成器
         */
        public void applyDefault(CacheOperation.Builder builder) {
            // 没初始化过
            if (!this.initialized) {
                CacheConfig annotation = AnnotatedElementUtils.findMergedAnnotation(this.target, CacheConfig.class);
                if (annotation != null) {
                    // 拿到注解里面的值,设置到属性中
                    this.cacheNames = annotation.cacheNames();
                    this.keyGenerator = annotation.keyGenerator();
                    this.cacheManager = annotation.cacheManager();
                    this.cacheResolver = annotation.cacheResolver();
                }
                // 标记 初始化了
                this.initialized = true;
            }

            // 只有当 @Cacheable、@CacheEvict、@CachePut 没有设置值是,才会使用 @CacheConfig 的值
            if (builder.getCacheNames().isEmpty() && this.cacheNames != null) {
                builder.setCacheNames(this.cacheNames);
            }
            if (!StringUtils.hasText(builder.getKey()) && !StringUtils.hasText(builder.getKeyGenerator()) &&
                StringUtils.hasText(this.keyGenerator)) {
                builder.setKeyGenerator(this.keyGenerator);
            }

            if (StringUtils.hasText(builder.getCacheManager()) || StringUtils.hasText(builder.getCacheResolver())) {
                // One of these is set so we should not inherit anything
            } else if (StringUtils.hasText(this.cacheResolver)) {
                builder.setCacheResolver(this.cacheResolver);
            } else if (StringUtils.hasText(this.cacheManager)) {
                builder.setCacheManager(this.cacheManager);
            }
        }
    }

}

CacheManager

缓存管理器

/**
 * Spring 的中央缓存管理器 SPI。
 *
 * <p>允许检索命名的 {@link Cache} 区域。
 *
 * @author Costin Leau
 * @author Sam Brannen
 * @since 3.1
 */
public interface CacheManager {

    /**
    * 获取与给定名称关联的缓存。
     * @param name 命名缓存标识符(不得为 {@code null})
     * @return 关联的缓存,如果此类缓存, 不存在或无法创建则为 {@code null}
     */
    @Nullable
    Cache getCache(String name);

    /**
     * 获取此管理器已知的缓存名称的集合。
     * @return 缓存管理器已知的所有缓存的名称
     */
    Collection<String> getCacheNames();

}



public abstract class AbstractCacheManager implements CacheManager, InitializingBean {

	private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);

	private volatile Set<String> cacheNames = Collections.emptySet();


	// Early cache initialization on startup

	@Override
	public void afterPropertiesSet() {
		initializeCaches();
	}

	/**
	 * Initialize the static configuration of caches.
	 * <p>Triggered on startup through {@link #afterPropertiesSet()};
	 * can also be called to re-initialize at runtime.
	 * @since 4.2.2
	 * @see #loadCaches()
	 */
	public void initializeCaches() {
		Collection<? extends Cache> caches = loadCaches();

		synchronized (this.cacheMap) {
			this.cacheNames = Collections.emptySet();
			this.cacheMap.clear();
			Set<String> cacheNames = new LinkedHashSet<>(caches.size());
			for (Cache cache : caches) {
				String name = cache.getName();
				this.cacheMap.put(name, decorateCache(cache));
				cacheNames.add(name);
			}
			this.cacheNames = Collections.unmodifiableSet(cacheNames);
		}
	}

	/**
	 * Load the initial caches for this cache manager.
	 * <p>Called by {@link #afterPropertiesSet()} on startup.
	 * The returned collection may be empty but must not be {@code null}.
	 */
	protected abstract Collection<? extends Cache> loadCaches();


	// Lazy cache initialization on access

	@Override
	@Nullable
	public Cache getCache(String name) {
		// Quick check for existing cache...
		Cache cache = this.cacheMap.get(name);
		if (cache != null) {
			return cache;
		}

		// The provider may support on-demand cache creation...
		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;
	}

	@Override
	public Collection<String> getCacheNames() {
		return this.cacheNames;
	}


	// Common cache initialization delegates for subclasses

	/**
	 * Check for a registered cache of the given name.
	 * In contrast to {@link #getCache(String)}, this method does not trigger
	 * the lazy creation of missing caches via {@link #getMissingCache(String)}.
	 * @param name the cache identifier (must not be {@code null})
	 * @return the associated Cache instance, or {@code null} if none found
	 * @since 4.1
	 * @see #getCache(String)
	 * @see #getMissingCache(String)
	 */
	@Nullable
	protected final Cache lookupCache(String name) {
		return this.cacheMap.get(name);
	}

	/**
	 * Dynamically register an additional Cache with this manager.
	 * @param cache the Cache to register
	 * @deprecated as of Spring 4.3, in favor of {@link #getMissingCache(String)}
	 */
	@Deprecated
	protected final void addCache(Cache cache) {
		String name = cache.getName();
		synchronized (this.cacheMap) {
			if (this.cacheMap.put(name, decorateCache(cache)) == null) {
				updateCacheNames(name);
			}
		}
	}

	/**
	 * Update the exposed {@link #cacheNames} set with the given name.
	 * <p>This will always be called within a full {@link #cacheMap} lock
	 * and effectively behaves like a {@code CopyOnWriteArraySet} with
	 * preserved order but exposed as an unmodifiable reference.
	 * @param name the name of the cache to be added
	 */
	private void updateCacheNames(String name) {
		Set<String> cacheNames = new LinkedHashSet<>(this.cacheNames);
		cacheNames.add(name);
		this.cacheNames = Collections.unmodifiableSet(cacheNames);
	}


	// Overridable template methods for cache initialization

	/**
	 * Decorate the given Cache object if necessary.
	 * @param cache the Cache object to be added to this CacheManager
	 * @return the decorated Cache object to be used instead,
	 * or simply the passed-in Cache object by default
	 */
	protected Cache decorateCache(Cache cache) {
		return cache;
	}

	/**
	 * Return a missing cache with the specified {@code name}, or {@code null} if
	 * such a cache does not exist or could not be created on demand.
	 * <p>Caches may be lazily created at runtime if the native provider supports it.
	 * If a lookup by name does not yield any result, an {@code AbstractCacheManager}
	 * subclass gets a chance to register such a cache at runtime. The returned cache
	 * will be automatically added to this cache manager.
	 * @param name the name of the cache to retrieve
	 * @return the missing cache, or {@code null} if no such cache exists or could be
	 * created on demand
	 * @since 4.1
	 * @see #getCache(String)
	 */
	@Nullable
	protected Cache getMissingCache(String name) {
		return null;
	}

}

Cache

缓存

public interface Cache {

	/**
	 * 返回缓存名称。
	 */
	String getName();

	/**
	 *返回基础本机缓存提供程序。
	 */
	Object getNativeCache();

	@Nullable
	ValueWrapper get(Object key);

	@Nullable
	<T> T get(Object key, @Nullable Class<T> type);

	@Nullable
	<T> T get(Object key, Callable<T> valueLoader);

	void put(Object key, @Nullable Object value);

	@Nullable
	default ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
		ValueWrapper existingValue = get(key);
		if (existingValue == null) {
			put(key, value);
		}
		return existingValue;
	}

	/**
	 * 如果存在此键的映射,请从此缓存中逐出该映射。
	 * <p>实际逐出可以异步执行,也可以延迟执行后续查找可能仍能看到该条目。
	 * 例如,事务性缓存装饰器可能就是这种情况。
	 * 使用 {@link #evictIfPresent} 保证立即删除。
	 * @param key the key whose mapping is to be removed from the cache
	 * @see #evictIfPresent(Object)
	 */
	void evict(Object key);

	default boolean evictIfPresent(Object key) {
		evict(key);
		return false;
	}

	/**
	 * 通过删除所有映射来清除缓存。
	 * <p>实际清算可以异步或延迟进行
	 * 时尚,后续查找可能仍能看到条目。
	 * 例如,事务性缓存装饰器可能就是这种情况。
	 * 使用 {@link #invalidate()} 保证立即删除条目。
	 * @see #invalidate()
	 */
	void clear();

	/**
	 * 通过删除所有映射使缓存失效,期望所有
	 * 条目在后续查找时立即不可见。
	 * @return {@code true} if the cache was known to have mappings before,
	 * {@code false} if it did not (or if prior presence of entries could
	 * not be determined)
	 * @since 5.2
	 * @see #clear()
	 */
	default boolean invalidate() {
		clear();
		return false;
	}


	/**
	 * A (wrapper) object representing a cache value.
	 */
	@FunctionalInterface
	interface ValueWrapper {

		/**
		 * Return the actual value in the cache.
		 */
		@Nullable
		Object get();
	}

	@SuppressWarnings("serial")
	class ValueRetrievalException extends RuntimeException {

		@Nullable
		private final Object key;

		public ValueRetrievalException(@Nullable Object key, Callable<?> loader, Throwable ex) {
			super(String.format("Value for key '%s' could not be loaded using '%s'", key, loader), ex);
			this.key = key;
		}

		@Nullable
		public Object getKey() {
			return this.key;
		}
	}

}

CacheResolver

作用:通过CacheManager获取Cache。

public interface CacheResolver {

    /**
     * 返回用于指定调用的缓存。
     * @param context the context of the particular invocation
     * @return the cache(s) to use (never {@code null})
     * @throws IllegalStateException if cache resolution failed
     */
    Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context);

}

BeanFactoryCacheOperationSourceAdvisor

切面

public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

    @Nullable
    private CacheOperationSource cacheOperationSource;

    private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
       @Override
       @Nullable
       protected CacheOperationSource getCacheOperationSource() {
          return cacheOperationSource;
       }
    };


    /**
     * Set the cache operation attribute source which is used to find cache
     * attributes. This should usually be identical to the source reference
     * set on the cache interceptor itself.
     */
    public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {
       this.cacheOperationSource = cacheOperationSource;
    }

    /**
     * Set the {@link ClassFilter} to use for this pointcut.
     * Default is {@link ClassFilter#TRUE}.
     */
    public void setClassFilter(ClassFilter classFilter) {
       this.pointcut.setClassFilter(classFilter);
    }

    @Override
    public Pointcut getPointcut() {
       return this.pointcut;
    }

}

CacheOperationSourcePointcut

切点

abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {

    protected CacheOperationSourcePointcut() {
        setClassFilter(new CacheOperationSourceClassFilter());
    }


    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        // 拿到解析注解的东西
        CacheOperationSource cas = getCacheOperationSource();
        /**
         * 解析到注解 就是true,表示匹配。默认是 AnnotationCacheOperationSource 执行的是其父类方法
         *      {@link AbstractFallbackCacheOperationSource#getCacheOperations(Method, Class)}
         * */
        return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)));
    }

    /**
     * Obtain the underlying {@link CacheOperationSource} (may be {@code null}).
     * To be implemented by subclasses.
     */
    @Nullable
    protected abstract CacheOperationSource getCacheOperationSource();


    /**
     * {@link ClassFilter} that delegates to {@link CacheOperationSource#isCandidateClass}
     * for filtering classes whose methods are not worth searching to begin with.
     */
    private class CacheOperationSourceClassFilter implements ClassFilter {

        @Override
        public boolean matches(Class<?> clazz) {
            // 是 CacheManager 就不匹配
            if (CacheManager.class.isAssignableFrom(clazz)) {
                return false;
            }

            CacheOperationSource cas = getCacheOperationSource();
            // 可以理解成都是true
            return (cas == null || cas.isCandidateClass(clazz));
        }
    }

}

CacheInterceptor

增强

这里可以看到,增强逻辑实在父类的execute方法里面。

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

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

    /**
     * 默认是 SimpleKeyGenerator
     */
    private SingletonSupplier<KeyGenerator> keyGenerator = SingletonSupplier.of(SimpleKeyGenerator::new);

    /**
     * 默认是 null
     */
    @Nullable
    private SingletonSupplier<CacheResolver> cacheResolver;

    @Nullable
    private BeanFactory beanFactory;

    private boolean initialized = false;

    public void configure(
            @Nullable Supplier<CacheErrorHandler> errorHandler, @Nullable Supplier<KeyGenerator> keyGenerator,
            @Nullable Supplier<CacheResolver> cacheResolver, @Nullable Supplier<CacheManager> cacheManager) {

        this.errorHandler = new SingletonSupplier<>(errorHandler, SimpleCacheErrorHandler::new);
        this.keyGenerator = new SingletonSupplier<>(keyGenerator, SimpleKeyGenerator::new);
        this.cacheResolver = new SingletonSupplier<>(cacheResolver,
                () -> SimpleCacheResolver.of(SupplierUtils.resolve(cacheManager)));
    }

    public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
        Assert.notEmpty(cacheOperationSources, "At least 1 CacheOperationSource needs to be specified");
        this.cacheOperationSource = (cacheOperationSources.length > 1 ?
                new CompositeCacheOperationSource(cacheOperationSources) : cacheOperationSources[0]);
    }

    public void setCacheOperationSource(@Nullable CacheOperationSource cacheOperationSource) {
        this.cacheOperationSource = cacheOperationSource;
    }

    @Nullable
    public CacheOperationSource getCacheOperationSource() {
        return this.cacheOperationSource;
    }

    public void setKeyGenerator(KeyGenerator keyGenerator) {
        this.keyGenerator = SingletonSupplier.of(keyGenerator);
    }

    public KeyGenerator getKeyGenerator() {
        return this.keyGenerator.obtain();
    }

    public void setCacheResolver(@Nullable CacheResolver cacheResolver) {
        this.cacheResolver = SingletonSupplier.ofNullable(cacheResolver);
    }

    @Nullable
    public CacheResolver getCacheResolver() {
        return SupplierUtils.resolve(this.cacheResolver);
    }

    public void setCacheManager(CacheManager cacheManager) {
        this.cacheResolver = SingletonSupplier.of(new SimpleCacheResolver(cacheManager));
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    @Override
    public void afterPropertiesSet() {
        Assert.state(getCacheOperationSource() != null, "The 'cacheOperationSources' property is required: " +
                "If there are no cacheable methods, then don't use a cache aspect.");
    }

    @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;
    }

    protected String methodIdentification(Method method, Class<?> targetClass) {
        Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
        return ClassUtils.getQualifiedMethodName(specificMethod);
    }

    protected Collection<? extends Cache> getCaches(
            CacheOperationInvocationContext<CacheOperation> context, CacheResolver cacheResolver) {

        // 就是通过注解写的 name 从 CacheManager 中获取 Cache 实例
        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;
    }

    protected CacheOperationContext getOperationContext(
            CacheOperation operation, Method method, Object[] args, Object target, Class<?> targetClass) {
        /**
         * 将 CacheOperation 装饰成 CacheOperationMetadata 对象
         * 该对象的关键属性:KeyGenerator、CacheResolver,而CacheResolver里面组合了 CacheManager
         *
         * 注:实例化 CacheOperationMetadata 会检验容器中是否有 CacheManager
         * */
        CacheOperationMetadata metadata = getCacheOperationMetadata(operation, method, targetClass);
        /**
         * 装饰成 CacheOperationContext
         * 主要是拿到 CacheOperation 对应的 Cache 和 将方法参数铺平(就是存在可变参数,就将可变参数铺平)
         * */
        return new CacheOperationContext(metadata, args, target);
    }

    protected CacheOperationMetadata getCacheOperationMetadata(
            CacheOperation operation, Method method, Class<?> targetClass) {

        // 生成key
        CacheOperationCacheKey cacheKey = new CacheOperationCacheKey(operation, method, targetClass);
        // 读缓存
        CacheOperationMetadata metadata = this.metadataCache.get(cacheKey);
        if (metadata == null) {
            KeyGenerator operationKeyGenerator;
            if (StringUtils.hasText(operation.getKeyGenerator())) {
                // 从容器中获取 KeyGenerator
                operationKeyGenerator = getBean(operation.getKeyGenerator(), KeyGenerator.class);
            } else {
                // 获取默认的 默认是 SimpleKeyGenerator
                operationKeyGenerator = getKeyGenerator();
            }
            CacheResolver operationCacheResolver;
            if (StringUtils.hasText(operation.getCacheResolver())) {
                // 从容器中获取 CacheResolver
                operationCacheResolver = getBean(operation.getCacheResolver(), CacheResolver.class);
            } else if (StringUtils.hasText(operation.getCacheManager())) {
                // 从容器中获取 CacheManager
                CacheManager cacheManager = getBean(operation.getCacheManager(), CacheManager.class);
                // 将 CacheManager 装饰成 SimpleCacheResolver
                operationCacheResolver = new SimpleCacheResolver(cacheManager);
            } else {
                /**
                 * 啥都没得,就获取默认的。
                 *
                 * 通过 CachingConfigurer 类型的bean设置的,如果设置了 cacheResolver 就返回,没有就判断有cacheManager,就装饰成SimpleCacheResolver返回
                 *   {@link CachingConfigurer#cacheResolver()}
                 *   {@link CachingConfigurer#cacheManager()}
                 *
                 * Tips:也就是说CachingConfigurer必须得设置 CacheResolver或者CacheManager 其中一个,否则这里拿不到
                 * */
                operationCacheResolver = getCacheResolver();
                /**
                 * 非空校验
                 *
                 * 也就是说CachingConfigurer必须得设置 CacheResolver或者CacheManager 其中一个,否则到这一步就报错
                 * */
                Assert.state(operationCacheResolver != null, "No CacheResolver/CacheManager set");
            }
            metadata = new CacheOperationMetadata(operation, method, targetClass,
                    operationKeyGenerator, operationCacheResolver);
            // 缓存起来
            this.metadataCache.put(cacheKey, metadata);
        }
        return metadata;
    }

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

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

    @Nullable
    protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
        /**
         * 这个bean实例化完就会设置为true
         * {@link CacheAspectSupport#afterSingletonsInstantiated()}
         * */
        // 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) {
                // 返回的是方法或者类上 @Cacheable、@CacheEvict、@CachePut 的解析结果
                Collection<CacheOperation> operations = cacheOperationSource.getCacheOperations(method, targetClass);
                // 不是空,表示方法上有缓存注解
                if (!CollectionUtils.isEmpty(operations)) {
                    /**
                     * 将 operations、方法、方法参数、执行方法的对象和执行方法的类型 装饰成 CacheOperationContexts 对象
                     * 然后 invoke
                     * */
                    return execute(invoker, method,
                            new CacheOperationContexts(operations, method, args, target, targetClass));
                }
            }
        }

        return invoker.invoke();
    }

    @Nullable
    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) {
        /**
         * 是同步的。就是 @Cacheable(sync = true)
         * */
        // Special handling of synchronized invocation
        if (contexts.isSynchronized()) {
            // 同步的方法上只允许有一个 缓存注解,所以拿第一个就行了
            CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();
            /**
             * 条件通过。
             * 有设置 @Cacheable(condition = "#root.methodName.startsWith('x')") 就解析SpEL看看结果是true就是通过
             * 没有设置condition属性,就直接是true
             *
             * 很简单,就是将 方法的参数和一些固定参数(method、target、targetClass、args、caches) 构造出 EvaluationContext 然后使用 SpelExpressionParser 解析 SpEL表达式
             *      {@link CacheOperationContext#isConditionPassing(Object)}
             * */
            if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
                /**
                 * 生成key。
                 * 如果有设置 @Cacheable(key = "#p1"), SpEL的值+Method+Target生成的key 作为缓存的key
                 * 没有指定key属性,就根据{@link KeyGenerator#generate(Object, Method, Object...)} 返回值作为缓存的key
                 * */
                Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
                // 同步的方法上只允许有一个 缓存注解,所以拿第一个Cache实例就行了
                Cache cache = context.getCaches().iterator().next();
                try {
                    /**
                     * handleSynchronizedGet 就是 使用 key从Cache中获取,获取不到就invoke方法获取值,会将方法返回值值存到 Cache 中。
                     *
                     * 存入Cache的细节:
                     *  1. 如果方法返回值是Optional类型的,会 {@link Optional#get()} 存到缓存
                     *  2. 如果Cache配了序列化器,会将值序列化在存到缓存中,获取的时候也会判断是否有序列化器 有就反序列化值
                     *
                     * wrapCacheValue 就是如果方法的返回值是 Optional 类型的,就包装一下
                     *
                     * 注:并没有看到具体的同步操作,是不是假的同步呀 能不能同步 还得看具体的 {@link Cache#get(Object)} 如何实现的
                     *      莫非,所谓的同步就是校验 方法上只能有一个  @Cacheable 注解???
                     *      看了官方文档,这个同步的实现得看具体的Cache实例 https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#cache-annotations-cacheable-synchronized
                     * */
                    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);
            }
        }

        /**
         * 清空缓存,就看是根据key删除 还是 直接清空整个Cache
         * 比如 @CacheEvict(allEntries = true) 就是清空整个缓存
         * */
        // Process any early evictions
        processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
                CacheOperationExpressionEvaluator.NO_RESULT);
        /**
         * 就是遍历 CacheOperationContext,条件通过的,在遍历 Cache 根据key获取缓存值,找到就返回
         * */
        // Check if we have a cached item matching the conditions
        Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));

        /**
         * 就是没有缓存的值,那就构造 CachePutRequest ,就是用来将 方法返回值 存到 Cache中的
         * {@link CachePutRequest#apply(Object)}
         *
         * 该属性是记录符合条件的 @CachePut + @Cacheable
         * */
        // Collect puts from any @Cacheable miss, if no cached item is found
        List<CachePutRequest> cachePutRequests = new ArrayList<>();
        if (cacheHit == null) {
            // 收集满足 condition 的 CacheableOperation
            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();
            // 是否需要装饰为Optional对象
            returnValue = wrapCacheValue(method, cacheValue);
        } else {
            // 放行方法,拿到返回值
            // Invoke the method if we don't have a cache hit
            returnValue = invokeOperation(invoker);
            // 是否需要解构Optional对象,拿到其值
            cacheValue = unwrapReturnValue(returnValue);
        }

        /**
         * 收集符合条件的@CachePut
         * */
        // Collect any explicit @CachePuts
        collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);

        // Process any collected put requests, either from @CachePut or a @Cacheable miss
        for (CachePutRequest cachePutRequest : cachePutRequests) {
            /**
             * 就是就方法返回值 设置到 Cache 中,此时会进行 unless 的解析判断
             * {@link CacheOperationContext#canPutToCache(Object)}
             * */
            cachePutRequest.apply(cacheValue);
        }


        // 清空缓存
        // Process any late evictions
        processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);

        // 返回
        return returnValue;
    }

    @Nullable
    private Object handleSynchronizedGet(CacheOperationInvoker invoker, Object key, Cache cache) {
        InvocationAwareResult invocationResult = new InvocationAwareResult();
        /**
         * 这里就看你写的 Cache 实现类的方法咯,主要是对值的序列化处理
         * {@link ConcurrentMapCache#get(Object, Callable)}
         * */
        Object result = cache.get(key, () -> {
            // 缓存没有执行
            invocationResult.invoked = true;
            if (logger.isTraceEnabled()) {
                // 打印 没命中缓存的日志
                logger.trace("No cache entry for key '" + key + "' in cache " + cache.getName());
            }
            /**
             * 结构返回值,若返回值是Optional类型的,就 {@link Optional#get()}
             * */
            return unwrapReturnValue(invokeOperation(invoker));
        });
        if (!invocationResult.invoked && logger.isTraceEnabled()) {
            // 打印 命中缓存的日志
            logger.trace("Cache entry for key '" + key + "' found in cache '" + cache.getName() + "'");
        }
        // 返回结果
        return result;
    }

    @Nullable
    private Object wrapCacheValue(Method method, @Nullable Object cacheValue) {
        if (method.getReturnType() == Optional.class &&
                (cacheValue == null || cacheValue.getClass() != Optional.class)) {
            return Optional.ofNullable(cacheValue);
        }
        return cacheValue;
    }

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

    private boolean hasCachePut(CacheOperationContexts contexts) {
        // Evaluate the conditions *without* the result object because we don't have it yet...
        Collection<CacheOperationContext> cachePutContexts = contexts.get(CachePutOperation.class);
        Collection<CacheOperationContext> excluded = new ArrayList<>();
        for (CacheOperationContext context : cachePutContexts) {
            try {
                /**
                 * 条件不通过,就说明是不需要更新的
                 *
                 * 使用这个表示,SpEL不可以使用这个变量,要是用了就报错,但是下面捕获到异常并没有做处理,所以用了 也没事
                 * {@link CacheEvaluationContext#lookupVariable(String)}
                 * */
                if (!context.isConditionPassing(CacheOperationExpressionEvaluator.RESULT_UNAVAILABLE)) {
                    // 记录
                    excluded.add(context);
                }
            } catch (VariableNotAvailableException ex) {
                // Ignoring failure due to missing result, consider the cache put has to proceed
            }
        }
        // 不想等,说明是有需要执行的 CachePutOperation
        // Check if all puts have been excluded by condition
        return (cachePutContexts.size() != excluded.size());
    }

    private void processCacheEvicts(
            Collection<CacheOperationContext> contexts, boolean beforeInvocation, @Nullable Object result) {
        // 遍历所有的  CacheEvictOperation
        for (CacheOperationContext context : contexts) {
            CacheEvictOperation operation = (CacheEvictOperation) context.metadata.operation;
            /**
             * CacheEvictOperation 是调用前执行 且 满足条件
             * 就是 @CacheEvict(beforeInvocation = true)
             * */
            if (beforeInvocation == operation.isBeforeInvocation() && isConditionPassing(context, result)) {
                // 清空缓存
                performCacheEvict(context, operation, result);
            }
        }
    }

    private void performCacheEvict(
            CacheOperationContext context, CacheEvictOperation operation, @Nullable Object result) {

        Object key = null;
        // 遍历关联的Cache
        for (Cache cache : context.getCaches()) {
            /**
             * 就是 @CacheEvict(allEntries = true)
             * */
            if (operation.isCacheWide()) {
                logInvalidating(context, operation, null);
                // 清空整个 Cache
                doClear(cache, operation.isBeforeInvocation());
            } else {
                if (key == null) {
                    // 缓存的key
                    key = generateKey(context, result);
                }
                logInvalidating(context, operation, key);
                // 根据 key 清除 Cache 中存储的值
                doEvict(cache, key, operation.isBeforeInvocation());
            }
        }
    }

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

    /**
     * 仅查找传递条件的 {@link CacheableOperation} 的缓存项。
     * @param contexts the cacheable operations
     * @return a {@link Cache.ValueWrapper} holding the cached item,
     * or {@code null} if none is found
     */
    @Nullable
    private Cache.ValueWrapper findCachedItem(Collection<CacheOperationContext> contexts) {
        Object result = CacheOperationExpressionEvaluator.NO_RESULT;
        // 就是方法上写了多个 @Cacheable
        for (CacheOperationContext context : contexts) {
            // 匹配
            if (isConditionPassing(context, result)) {
                // 生成key
                Object key = generateKey(context, result);
                /**
                 * 因为一个 @Cacheable(cacheNames = {"a", "b"}) 是可以写多个 Cache的,所以会遍历所有的 Cache 根据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;
    }

    /**
     * Collect the {@link CachePutRequest} for all {@link CacheOperation} using
     * the specified result item.
     * @param contexts the contexts to handle
     * @param result the result item (never {@code null})
     * @param putRequests the collection to update
     */
    private void collectPutRequests(Collection<CacheOperationContext> contexts,
                                    @Nullable Object result, Collection<CachePutRequest> putRequests) {

        for (CacheOperationContext context : contexts) {
            // 条件通过
            if (isConditionPassing(context, result)) {
                Object key = generateKey(context, result);
                // 构造器 CachePutRequest
                putRequests.add(new CachePutRequest(context, key));
            }
        }
    }

    @Nullable
    private Cache.ValueWrapper findInCaches(CacheOperationContext context, Object key) {
        // 遍历 Cache
        for (Cache cache : context.getCaches()) {
            // 就是根据 key 获取咯
            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) {
        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) {
        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) {

            this.contexts = new LinkedMultiValueMap<>(operations.size());
            for (CacheOperation op : operations) {
                /**
                 * 将 CacheOperation 转成 CacheOperationContext
                 * */
                this.contexts.add(op.getClass(), getOperationContext(op, method, args, target, targetClass));
            }
            /**
             * 推断是否同步。
             *
             * 是对 @Cacheable(sync=true) 的重重校验:
             *  1. 没有 @Cacheable(sync=true) 就 `return false`
             *  2. 有`sync=true`的情况
             *      2.1 只允许写一个缓存注解
             *      2.2 cacheNames 属性,只能写一个name
             *      2.3 unless 属性,不能设置
             *      注:不满足这三点就直接报错 `throw new IllegalStateException`
             * */
            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;
        }

        private boolean determineSyncFlag(Method method) {
            // 拿到 CacheableOperation 即 @Cacheable 的解析结果
            List<CacheOperationContext> cacheOperationContexts = this.contexts.get(CacheableOperation.class);
            if (cacheOperationContexts == null) {  // no @Cacheable operation at all
                return false;
            }
            boolean syncEnabled = false;
            for (CacheOperationContext cacheOperationContext : cacheOperationContexts) {
                // 是同步
                if (((CacheableOperation) cacheOperationContext.getOperation()).isSync()) {
                    syncEnabled = true;
                    break;
                }
            }
            // 是同步的,需要进一步校验
            if (syncEnabled) {
                // 开启同步,就不支持多个注解了
                if (this.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 + "'");
                }
                CacheOperationContext cacheOperationContext = cacheOperationContexts.iterator().next();
                // 到这里,说明就写了一个 @Cacheable ,所以拿第一个就行
                CacheableOperation operation = (CacheableOperation) cacheOperationContext.getOperation();
                // 不支持多个 Cache
                if (cacheOperationContext.getCaches().size() > 1) {
                    throw new IllegalStateException(
                            "@Cacheable(sync=true) only allows a single cache on '" + operation + "'");
                }
                // 不支持 unless 规则
                if (StringUtils.hasText(operation.getUnless())) {
                    throw new IllegalStateException(
                            "@Cacheable(sync=true) does not support unless attribute on '" + operation + "'");
                }
                return true;
            }
            return false;
        }
    }


    /**
     * Metadata of a cache operation that does not depend on a particular invocation
     * which makes it a good candidate for caching.
     */
    protected static class CacheOperationMetadata {

        private final CacheOperation operation;

        private final Method method;

        private final Class<?> targetClass;

        private final Method targetMethod;

        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;
            this.targetMethod = (!Proxy.isProxyClass(targetClass) ?
                    AopUtils.getMostSpecificMethod(method, targetClass) : this.method);
            /**
             * Method对象+类型 作为 methodKey,在生成缓存key的时候会使用到,
             * 也就是说即使是多例bean,也能保证执行同一个cache方法 也能生成同样的缓存key,从而可以使用同样的缓存值
             * */
            this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass);
            this.keyGenerator = keyGenerator;
            this.cacheResolver = cacheResolver;
        }
    }


    /**
     * A {@link CacheOperationInvocationContext} context for a {@link CacheOperation}.
     */
    protected class CacheOperationContext implements CacheOperationInvocationContext<CacheOperation> {

        private final CacheOperationMetadata metadata;

        /**
         * 执行方法的入参。
         * 注:如果最后一个参数是可变参数,会将可变参数铺平
         */
        private final Object[] args;

        private final Object target;

        /**
         * 这个 CacheOperation 对应的 Cache
         */
        private final Collection<? extends Cache> caches;

        /**
         * 这个 CacheOperation 对应的 cacheName
         */
        private final Collection<String> cacheNames;

        @Nullable
        private Boolean conditionPassing;

        public CacheOperationContext(CacheOperationMetadata metadata, Object[] args, Object target) {
            this.metadata = metadata;
            /**
             * 处理方法的最后一个参数是可变参数的情况。若是可变参数,就拿到最后一个参数,将其铺平,和其它参数放在一块
             *
             * 目的是:在生成缓存key时会根据方法参数来生成,方法的入参相同应当是同一个key。
             *        但是动态参数的入参每次都是new数组来存储,这就导致方法的参数是一样的,但是动态参数是不同的对象,
             *        所以这里需要将动态参数给铺平
             * */
            this.args = extractArgs(metadata.method, args);
            this.target = target;
            /**
             * 使用 CacheResolver 通过注解设置的cacheName 拿到对应的 Cache 实例,
             * 本质还是使用的 {@link CacheManager#getCache(String)},
             * 常用的CacheManager都支持,没有预设Cache就在getCache的时候创建
             * */
            this.caches = CacheAspectSupport.this.getCaches(this, metadata.cacheResolver);
            // 记录
            this.cacheNames = createCacheNames(this.caches);
        }

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

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

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

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

        /**
         * 如果最后一个参数是可变参数,就将可变参数 铺平,和其它参数放在一块
         * @param method 方法对象
         * @param args 方法参数,指的是方法被调用时的参数
         * @return
         */
        private Object[] extractArgs(Method method, Object[] args) {
            /**
             * 比如 public void a(int i,String... x) 就是变量参数
             * */
            // 参数列表不是可变参数
            if (!method.isVarArgs()) {
                return args;
            }
            /**
             * 因为最后一个参数是可变参数,所以拿到最后一个参数 铺平,和其它参数放在一块
             * */
            Object[] varArgs = ObjectUtils.toObjectArray(args[args.length - 1]);
            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;
        }

        /**
         * 是通过条件。
         * - 有设置 @Cacheable(condition = "#root.methodName.startsWith('x')") 就解析SpEL看看结果是ture就是通过
         * - 没有设置condition属性,就直接是true
         * @param result
         * @return
         */
        protected boolean isConditionPassing(@Nullable Object result) {
            /**
             * 每次执行方法都会为每一个 CacheOperation 构造一个新的 CacheOperationContext 实例,所以这里可以这么判断
             * {@link CacheAspectSupport#execute(CacheOperationInvoker, Object, Method, Object[])}
             * */
            if (this.conditionPassing == null) {
                // 写了 condition 属性
                if (StringUtils.hasText(this.metadata.operation.getCondition())) {
                    // SpEL解析的构造上下文对象
                    EvaluationContext evaluationContext = createEvaluationContext(result);
                    // SpEL 解析表达式
                    this.conditionPassing = evaluator.condition(this.metadata.operation.getCondition(),
                            this.metadata.methodKey, evaluationContext);
                } else {
                    // 没有写 condition 属性 不需要判断
                    this.conditionPassing = true;
                }
            }
            return this.conditionPassing;
        }

        /**
         * 可以设置缓存
         * @param value
         * @return
         */
        protected boolean canPutToCache(@Nullable Object value) {
            String unless = "";
            if (this.metadata.operation instanceof CacheableOperation) {
                unless = ((CacheableOperation) this.metadata.operation).getUnless();
            } else if (this.metadata.operation instanceof CachePutOperation) {
                unless = ((CachePutOperation) this.metadata.operation).getUnless();
            }
            /**
             * 写了 unless 条件
             * @Cacheable(unless = "#result != null ")
             * */
            if (StringUtils.hasText(unless)) {
                // 构造 EvaluationContext,就是设置根对象,方法参数的变量,返回值变量
                EvaluationContext evaluationContext = createEvaluationContext(value);
                // 解析 SpEL ,解析结果是 true 就是不可以更新缓存,所以是 !
                return !evaluator.unless(unless, this.metadata.methodKey, evaluationContext);
            }
            // 没写 unless 直接返回true
            return true;
        }

        /**
         * 计算缓存的key。
         * - 如果有设置 @Cacheable(key = "#p1"), SpEL的值+Method+Target生成的key 作为缓存的key
         * - 没有指定key属性,就根据{@link KeyGenerator#generate(Object, Method, Object...)} 返回值作为缓存的key
         *
         * Compute the key for the given caching operation.
         */
        @Nullable
        protected Object generateKey(@Nullable Object result) {
            // 有key
            if (StringUtils.hasText(this.metadata.operation.getKey())) {
                // SpEL解析的上下文对象
                EvaluationContext evaluationContext = createEvaluationContext(result);
                // 就是拿到 SpEL表达式的值+methodKey 作为key
                return evaluator.key(this.metadata.operation.getKey(), this.metadata.methodKey, evaluationContext);
            }
            /**
             * 没有key,就使用 keyGenerator 生成key
             *
             * 默认的SimpleKeyGenerator 是只根据args来生成key的 {@link SimpleKeyGenerator#generate(Object, Method, Object...)}
             * */
            return this.metadata.keyGenerator.generate(this.target, this.metadata.method, this.args);
        }

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

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

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

        private Collection<String> createCacheNames(Collection<? extends Cache> caches) {
            Collection<String> names = new ArrayList<>();
            for (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) {
            /**
             * @Cacheable(unless = "#result != null ")
             *  1. 指定了unless属性,就执行SpEL,结果是false 才可以设置缓存
             *  2. 没有指定unless属性,就是可以设置缓存
             * */
            if (this.context.canPutToCache(result)) {
                for (Cache cache : this.context.getCaches()) {
                    // 根据key往Cache中设置缓存
                    doPut(cache, this.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;
            this.methodCacheKey = new AnnotatedElementKey(method, targetClass);
        }
    }

    /**
     * Internal holder class for recording that a cache method was invoked.
     */
    private static class InvocationAwareResult {

        boolean invoked;

    }

}
public abstract class AbstractCacheInvoker {

    /**
     * 默认是 SimpleCacheErrorHandler
     */
    protected SingletonSupplier<CacheErrorHandler> errorHandler;

    /**
     * Return the {@link CacheErrorHandler} to use.
     */
    public CacheErrorHandler getErrorHandler() {
        return this.errorHandler.obtain();
    }


    /**
     * Execute {@link Cache#get(Object)} on the specified {@link Cache} and
     * invoke the error handler if an exception occurs. Return {@code null}
     * if the handler does not throw any exception, which simulates a cache
     * miss in case of error.
     * @see Cache#get(Object)
     */
    @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
        }
    }

    /**
     * Execute {@link Cache#put(Object, Object)} on the specified {@link Cache}
     * and invoke the error handler if an exception occurs.
     */
    protected void doPut(Cache cache, Object key, @Nullable Object result) {
        try {
            cache.put(key, result);
        } catch (RuntimeException ex) {
            getErrorHandler().handleCachePutError(ex, cache, key, result);
        }
    }

    /**
     * Execute {@link Cache#evict(Object)}/{@link Cache#evictIfPresent(Object)} on the
     * specified {@link Cache} and invoke the error handler if an exception occurs.
     */
    protected void doEvict(Cache cache, Object key, boolean immediate) {
        try {
            if (immediate) {
                // 移除key对应的缓存
                cache.evictIfPresent(key);
            } else {
                // 移除key对应的缓存
                cache.evict(key);
            }
        } catch (RuntimeException ex) {
            getErrorHandler().handleCacheEvictError(ex, cache, key);
        }
    }

    /**
     * Execute {@link Cache#clear()} on the specified {@link Cache} and
     * invoke the error handler if an exception occurs.
     */
    protected void doClear(Cache cache, boolean immediate) {
        try {
            if (immediate) {
                // 也是清空,就看具体的 Cache 有啥特殊写法了
                cache.invalidate();
            } else {
                // 清空整个缓存
                cache.clear();
            }
        } catch (RuntimeException ex) {
            // 处理异常
            getErrorHandler().handleCacheClearError(ex, cache);
        }
    }

}

执行流程

@EnableCaching注解会import到容器CachingConfigurationSelector类,而CachingConfigurationSelector会向容器中注入AutoProxyRegistrar和ProxyCachingConfiguration。AutoProxyRegistrar在事务那里讲过了,这里主要看ProxyCachingConfiguration。

// 和事务一样的套路,向容器中注入切面、切点和通知,主要看通知的增强逻辑。
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {

    @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;
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public CacheOperationSource cacheOperationSource() {
        /**
         * 用来解析 方法->类 上 @Caching、@Cacheable、@CacheEvict、@CachePut、@CacheConfig 的
         * */
        return new AnnotationCacheOperationSource();
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public CacheInterceptor cacheInterceptor(CacheOperationSource cacheOperationSource) {
        CacheInterceptor interceptor = new CacheInterceptor();
        // 配置
        interceptor.configure(this.errorHandler, this.keyGenerator, this.cacheResolver, this.cacheManager);
        // 用来解析 @Caching、@Cacheable、@CacheEvict、@CachePut 的
        interceptor.setCacheOperationSource(cacheOperationSource);
        return interceptor;
    }

}

由上述代码可以看到,增强逻辑在CacheInterceptor中。而CacheInterceptor其实什么也没做,调用的是父类CacheAspectSupport的execute方法。

代码如下,可以看到CacheAspectSupport将解析出来的所有注解信息封装到了CacheOperationContexts中。

CacheAspectSupport:
@Nullable
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
    /**
     * 这个bean实例化完就会设置为true
     * {@link CacheAspectSupport#afterSingletonsInstantiated()}
     * */
    // 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) {
            // 返回的是方法或者类上 @Cacheable、@CacheEvict、@CachePut 的解析结果
            Collection<CacheOperation> operations = cacheOperationSource.getCacheOperations(method, targetClass);
            // 不是空,表示方法上有缓存注解
            if (!CollectionUtils.isEmpty(operations)) {
                /**
                 * 将 operations、方法、方法参数、执行方法的对象和执行方法的类型 装饰成 CacheOperationContexts 对象
                 * 然后 invoke
                 * */
                return execute(invoker, method,
                        new CacheOperationContexts(operations, method, args, target, targetClass));
            }
        }
    }

    return invoker.invoke();
}

CacheOperationContexts中存储了所有的注解信息,每个注解信息又被封装成了CacheOperationContext信息。

CacheOperationContext又是啥玩意,它里面其实就是对注解信息的进一步封装,其中的CacheOperationMetadata解析出了注解指定的KeyGenerator以及CacheResolver,后面要用。

综上所属,注解的信息都有了,下面的execute便是使用这些信息进行缓存的操作。

private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
    /**
     * 是同步的。就是 @Cacheable(sync = true)
     * */
    // Special handling of synchronized invocation
    if (contexts.isSynchronized()) {
        // 同步的方法上只允许有一个 缓存注解,所以拿第一个就行了
        CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();
        /**
         * 条件通过。
         * 有设置 @Cacheable(condition = "#root.methodName.startsWith('x')") 就解析SpEL看看结果是true就是通过
         * 没有设置condition属性,就直接是true
         *
         * 很简单,就是将 方法的参数和一些固定参数(method、target、targetClass、args、caches) 构造出 EvaluationContext 然后使用 SpelExpressionParser 解析 SpEL表达式
         *      {@link CacheOperationContext#isConditionPassing(Object)}
         * */
        if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
            /**
             * 生成key。
             * 如果有设置 @Cacheable(key = "#p1"), SpEL的值+Method+Target生成的key 作为缓存的key
             * 没有指定key属性,就根据{@link KeyGenerator#generate(Object, Method, Object...)} 返回值作为缓存的key
             * */
            Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
            // 同步的方法上只允许有一个 缓存注解,所以拿第一个Cache实例就行了
            Cache cache = context.getCaches().iterator().next();
            try {
                /**
                 * handleSynchronizedGet 就是 使用 key从Cache中获取,获取不到就invoke方法获取值,会将方法返回值值存到 Cache 中。
                 *
                 * 存入Cache的细节:
                 *  1. 如果方法返回值是Optional类型的,会 {@link Optional#get()} 存到缓存
                 *  2. 如果Cache配了序列化器,会将值序列化在存到缓存中,获取的时候也会判断是否有序列化器 有就反序列化值
                 *
                 * wrapCacheValue 就是如果方法的返回值是 Optional 类型的,就包装一下
                 *
                 * 注:并没有看到具体的同步操作,是不是假的同步呀 能不能同步 还得看具体的 {@link Cache#get(Object)} 如何实现的
                 *      莫非,所谓的同步就是校验 方法上只能有一个  @Cacheable 注解???
                 *      看了官方文档,这个同步的实现得看具体的Cache实例 https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#cache-annotations-cacheable-synchronized
                 * */
                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);
        }
    }

    /**
     * 清空缓存,就看是根据key删除 还是 直接清空整个Cache
     * 比如 @CacheEvict(allEntries = true) 就是清空整个缓存
     * */
    // Process any early evictions
    processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
            CacheOperationExpressionEvaluator.NO_RESULT);
    /**
     * 就是遍历 CacheOperationContext,条件通过的,在遍历 Cache 根据key获取缓存值,找到就返回
     * */
    // Check if we have a cached item matching the conditions
    Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));

    /**
     * 就是没有缓存的值,那就构造 CachePutRequest ,就是用来将 方法返回值 存到 Cache中的
     * {@link CachePutRequest#apply(Object)}
     *
     * 该属性是记录符合条件的 @CachePut + @Cacheable
     * */
    // Collect puts from any @Cacheable miss, if no cached item is found
    List<CachePutRequest> cachePutRequests = new ArrayList<>();
    if (cacheHit == null) {
        // 收集满足 condition 的 CacheableOperation
        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();
        // 是否需要装饰为Optional对象
        returnValue = wrapCacheValue(method, cacheValue);
    } else {
        // 放行方法,拿到返回值
        // Invoke the method if we don't have a cache hit
        returnValue = invokeOperation(invoker);
        // 是否需要解构Optional对象,拿到其值
        cacheValue = unwrapReturnValue(returnValue);
    }

    /**
     * 收集符合条件的@CachePut
     * */
    // Collect any explicit @CachePuts
    collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);

    // Process any collected put requests, either from @CachePut or a @Cacheable miss
    for (CachePutRequest cachePutRequest : cachePutRequests) {
        /**
         * 就是就方法返回值 设置到 Cache 中,此时会进行 unless 的解析判断
         * {@link CacheOperationContext#canPutToCache(Object)}
         * */
        cachePutRequest.apply(cacheValue);
    }


    // 清空缓存
    // Process any late evictions
    processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);

    // 返回
    return returnValue;
}

我们先看一下清空缓存的逻辑:

private void processCacheEvicts(
        Collection<CacheOperationContext> contexts, boolean beforeInvocation, @Nullable Object result) {
    // 遍历所有的  CacheEvictOperation
    for (CacheOperationContext context : contexts) {
        CacheEvictOperation operation = (CacheEvictOperation) context.metadata.operation;
        /**
         * CacheEvictOperation 是调用前执行 且 满足条件
         * 就是 @CacheEvict(beforeInvocation = true)
         * */
        if (beforeInvocation == operation.isBeforeInvocation() && isConditionPassing(context, result)) {
            // 清空缓存
            performCacheEvict(context, operation, result);
        }
    }
}
private void performCacheEvict(
        CacheOperationContext context, CacheEvictOperation operation, @Nullable Object result) {

    Object key = null;
    // 遍历关联的Cache
    for (Cache cache : context.getCaches()) {
        /**
         * 就是 @CacheEvict(allEntries = true)
         * */
        if (operation.isCacheWide()) {
            logInvalidating(context, operation, null);
            // 清空整个 Cache
            doClear(cache, operation.isBeforeInvocation());
        } else {
            if (key == null) {
                // 缓存的key
                key = generateKey(context, result);
            }
            logInvalidating(context, operation, key);
            // 根据 key 清除 Cache 中存储的值
            doEvict(cache, key, operation.isBeforeInvocation());
        }
    }
}

再看一下查找缓存的信息:

@Nullable
private Cache.ValueWrapper findCachedItem(Collection<CacheOperationContext> contexts) {
    Object result = CacheOperationExpressionEvaluator.NO_RESULT;
    // 就是方法上写了多个 @Cacheable
    for (CacheOperationContext context : contexts) {
        // 匹配 这里Spel表达式去解析 
        if (isConditionPassing(context, result)) {
            // 生成key
            Object key = generateKey(context, result);
            /**
             * 因为一个 @Cacheable(cacheNames = {"a", "b"}) 是可以写多个 Cache的,所以会遍历所有的 Cache 根据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;
}
@Nullable
private Cache.ValueWrapper findInCaches(CacheOperationContext context, Object key) {
    // 遍历 Cache
    for (Cache cache : context.getCaches()) {
        // 就是根据 key 获取咯
        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;
}

再来看一下put的代码:

public void apply(@Nullable Object result) {
    /**
     * @Cacheable(unless = "#result != null ")
     *  1. 指定了unless属性,就执行SpEL,结果是false 才可以设置缓存
     *  2. 没有指定unless属性,就是可以设置缓存
     * */
    if (this.context.canPutToCache(result)) {
        for (Cache cache : this.context.getCaches()) {
            // 根据key往Cache中设置缓存
            doPut(cache, this.key, result);
        }
    }
}
  • @CacheEvict(beforeInvocation = true)

    • 条件判断无法获取方法的返回值,是在方法执行前判断。
  • @Cacheable

    • condition 属性是在方法执行前判断,无法获取方法的返回值。
    • unless 属性是在方法执行后判断或者命中了缓存,可以获取方法的返回值或者是缓存的值。
  • @CachePut

    • condition 属性是在方法执行前判断,无法获取方法的返回值。
    • unless 属性是在方法执行后判断或者命中了缓存,可以获取方法的返回值或者是缓存的值。
  • @CacheEvict(beforeInvocation = false)

    • 条件判断可以获取方法的返回值,是在方法执行后判断。

CacheEvaluationContext 的变量解析过程,这就是为啥注解中写的SpEL表达式能用 #p1 #a1 #name 引用方法入参的原理

public class MethodBasedEvaluationContext extends StandardEvaluationContext {

    private final Method method;

    private final Object[] arguments;

    private final ParameterNameDiscoverer parameterNameDiscoverer;

    private boolean argumentsLoaded = false;


    public MethodBasedEvaluationContext(Object rootObject, Method method, Object[] arguments,
                                        ParameterNameDiscoverer parameterNameDiscoverer) {

        super(rootObject);
        this.method = method;
        this.arguments = arguments;
        // 解析参数列表 参数名称的
        this.parameterNameDiscoverer = parameterNameDiscoverer;
    }


    /**
     * SpEL 在使用变量时,会回调该方法返回变量
     * {@link StandardEvaluationContext#lookupVariable(String)}
     * @param name variable to lookup
     * @return
     */
    @Override
    @Nullable
    public Object lookupVariable(String name) {
        Object variable = super.lookupVariable(name);
        // 不为 null 就返回
        if (variable != null) {
            return variable;
        }
        // 还未加载过
        if (!this.argumentsLoaded) {
            // 加载参数
            lazyLoadArguments();
            this.argumentsLoaded = true;
            // 再次执行 就能查到了,查不到那就是真的没有
            variable = super.lookupVariable(name);
        }
        // 返回
        return variable;
    }

    /**
     * Load the param information only when needed.
     */
    protected void lazyLoadArguments() {
        // Shortcut if no args need to be loaded
        if (ObjectUtils.isEmpty(this.arguments)) {
            return;
        }

        // 方法的参数列表名称
        // Expose indexed variables as well as parameter names (if discoverable)
        String[] paramNames = this.parameterNameDiscoverer.getParameterNames(this.method);
        // 这是方法的参数列表名称
        int paramCount = (paramNames != null ? paramNames.length : this.method.getParameterCount());
        /**
         * 这个是方法执行时,传入的参数个数
         *
         * 这个是在实例化 CacheOperationContext {@link CacheAspectSupport.CacheOperationContext#CacheOperationContext(CacheAspectSupport.CacheOperationMetadata, Object[], Object)}
         * 解析方法的入参。解析入参,如果方法的最后一个参数是可变参数,会将可变参数铺平和其余入参放在数组中。
         *
         * 比如:
         * public abstract void a(String s,String... ss);
         * */
        int argsCount = this.arguments.length;
        // 遍历
        for (int i = 0; i < paramCount; i++) {
            Object value = null;
            /**
             * argsCount > paramCount 就是 方法的最后一个参数是可变参数 的情况
             * */
            if (argsCount > paramCount && i == paramCount - 1) {
                // 收集成数组
                // Expose remaining arguments as vararg array for last parameter
                value = Arrays.copyOfRange(this.arguments, i, argsCount);
            } else if (argsCount > i) {
                // Actual argument found - otherwise left as null
                value = this.arguments[i];
            }
            /**
             * 设置SpEL表达式变量
             *
             * "#a1 != null"
             * "#p1 != null"
             * "#ss != null"
             * */
            setVariable("a" + i, value);
            setVariable("p" + i, value);
            // 设置方法参数名为变量名
            if (paramNames != null && paramNames[i] != null) {
                setVariable(paramNames[i], value);
            }
        }
    }

}

Cache支持的SpEL变量说明:

NameLocationDescriptionExample
methodNameRoot object正在调用的方法的名称#root.methodName
methodRoot object正在调用的方法的名称#root.method.name
targetRoot object正在调用的方法的对象#root.target
targetClassRoot object正在调用的方法的对象的类#root.targetClass
argsRoot object当前调用的参数列表#root.args[0]
cachesRoot object当前方法使用的Cache列表#root.caches[0].name
Argument nameEvaluation context当前调用方法参数的变量#name | #a1 | #p1
resultEvaluation context方法执行的返回值#result

注:还可以使用 @beanName 引用BeanFactory中的bean对象