【spring源码】Spring-Cache源码解析

287 阅读13分钟

栗子

// 配置类
@Configuration
@EnableCaching
public static class Spr11124Config {
    // 注入 CacheManager
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager();
    }

    // 注入业务类TestService
    @Bean
    public TestService service() {
        return new TestServiceImpl();
    }
}
// 业务接口
public interface TestService {
    int single(int id);
}
// 业务实现类
public static class TestServiceImpl implements TestService {

    @Override
    @Cacheable("smallCache")
    public int single(int id) {
        System.out.println("执行逻辑。。。");
        return id;
    }
}

@Test
public void spr11124MultipleAnnotations2() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11124Config.class);

    TestService bean = context.getBean(TestService.class);
    System.out.println(bean.single(2));
    System.out.println(bean.single(2));
    context.close();
}

执行结果: image.png System.out.println("执行逻辑。。。"); 只执行了一次,说明第二次走了缓存。

缓存包类成员介绍

image.png

spring-cache-classes.png

源码分析

实例化bean

@EnableCaching 注解

类介绍

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

	/**
	 是否要创建基于子类 (CGLIB) 的代理,而不是创建标准的基于 Java 接口的代理。
     默认值为false 。仅当mode()设置为AdviceMode.PROXY 。
     请注意,将此属性设置为true将影响所有需要代理的 Spring 管理的 bean,
     而不仅仅是标记有@Cacheable的那些。
     例如,其他标有 Spring 的@Transactional注解的 bean 将同时升级为子类代理。
     这种方法在实践中没有负面影响,除非明确期望一种类型的代理与另一种类型的代理,例如在测试中。
	 */
	boolean proxyTargetClass() default false;

	/**
	 * 指示应如何应用缓存建议。
       默认值为AdviceMode.PROXY 。请注意,代理模式只允许通过代理拦截呼叫。同一类中的本地调用不能以这种方式被拦截;
       本地调用中此类方法上的缓存注释将被忽略,因为 Spring 的拦截器甚至不会在此类运行时场景中启动。
       对于更高级的拦截模式,请考虑将其切换为AdviceMode.ASPECTJ 。
	 */
	AdviceMode mode() default AdviceMode.PROXY;

	/**
	 * 当在特定连接点应用多个建议时,指示缓存顾问的执行顺序。
       默认值为Ordered.LOWEST_PRECEDENCE 。
	 */
	int order() default Ordered.LOWEST_PRECEDENCE;

}

该注解标识当前开启springcache功能。
boolean proxyTargetClass() default false; true:使用CGLIB代理模式;--false:使用JDK动态代理(默认)。
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;

源码解析

@EnableCaching 注解上有 @Import(CachingConfigurationSelector.class)
@import注解作用是向IOC容器中注入bean,也就是将CachingConfigurationSelector注入,相当于给CachingConfigurationSelector加上@component注解。

public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {

	private static final String PROXY_JCACHE_CONFIGURATION_CLASS =
			"org.springframework.cache.jcache.config.ProxyJCacheConfiguration";

	private static final String CACHE_ASPECT_CONFIGURATION_CLASS_NAME =
			"org.springframework.cache.aspectj.AspectJCachingConfiguration";

	private static final String JCACHE_ASPECT_CONFIGURATION_CLASS_NAME =
			"org.springframework.cache.aspectj.AspectJJCacheConfiguration";


	private static final boolean jsr107Present;

	private static final boolean jcacheImplPresent;

	static {
		ClassLoader classLoader = CachingConfigurationSelector.class.getClassLoader();
		jsr107Present = ClassUtils.isPresent("javax.cache.Cache", classLoader);
		jcacheImplPresent = ClassUtils.isPresent(PROXY_JCACHE_CONFIGURATION_CLASS, classLoader);
	}


	/**
	 * Returns {@link ProxyCachingConfiguration} or {@code AspectJCachingConfiguration}
	 * for {@code PROXY} and {@code ASPECTJ} values of {@link EnableCaching#mode()},
	 * respectively. Potentially includes corresponding JCache configuration as well.
	 */
	@Override
	public String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return getProxyImports();
			case ASPECTJ:
				return getAspectJImports();
			default:
				return null;
		}
	}

	/**
	 * Return the imports to use if the {@link AdviceMode} is set to {@link AdviceMode#PROXY}.
	 * <p>Take care of adding the necessary JSR-107 import if it is available.
	 */
	private String[] getProxyImports() {
		List<String> result = new ArrayList<>(3);
		// 注册aop的入口类InfrastructureAdvisorAutoProxyCreator
		result.add(AutoProxyRegistrar.class.getName());
		// 配置类
		result.add(ProxyCachingConfiguration.class.getName());
		if (jsr107Present && jcacheImplPresent) {
			result.add(PROXY_JCACHE_CONFIGURATION_CLASS);
		}
		return StringUtils.toStringArray(result);
	}

	/**
	 * Return the imports to use if the {@link AdviceMode} is set to {@link AdviceMode#ASPECTJ}.
	 * <p>Take care of adding the necessary JSR-107 import if it is available.
	 */
	private String[] getAspectJImports() {
		List<String> result = new ArrayList<>(2);
		result.add(CACHE_ASPECT_CONFIGURATION_CLASS_NAME);
		if (jsr107Present && jcacheImplPresent) {
			result.add(JCACHE_ASPECT_CONFIGURATION_CLASS_NAME);
		}
		return StringUtils.toStringArray(result);
	}

}

30 行:当该类被转换为BeanDefinition时,会调用 selectImports(),该类将需要注入的类的类名存储到数组中并返回。adviceMode 默认为“PROXY”,转掉getProxyImports()
45 行:需要把 AutoProxyRegistrar.class、ProxyCachingConfiguration.class 交给IOC管理

ProxyCachingConfiguration.class

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {

	// 注册Advisor
	@Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor() {
		BeanFactoryCacheOperationSourceAdvisor advisor = new BeanFactoryCacheOperationSourceAdvisor();
		// AnnotationCacheOperationSource
		advisor.setCacheOperationSource(cacheOperationSource());
		// CacheInterceptor 属性CacheOperationSource = AnnotationCacheOperationSource
		advisor.setAdvice(cacheInterceptor());
		if (this.enableCaching != null) {
			advisor.setOrder(this.enableCaching.<Integer>getNumber("order"));
		}
		return advisor;
	}

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

	// 增强 CacheInterceptor
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public CacheInterceptor cacheInterceptor() {
		CacheInterceptor interceptor = new CacheInterceptor();
		interceptor.configure(this.errorHandler, this.keyGenerator, this.cacheResolver, this.cacheManager);
		interceptor.setCacheOperationSource(cacheOperationSource());
		return interceptor;
	}

}

@Configuration类,用于注册缓存管理所需的 bean。就是把springcache功能需要的bean注入到IOC容器。
spring大多高级功能都是基于Aop实现的,而Aop又是根据动态代理实现的,使用Aop就需要定义Adviser,一个Adviser包含切点(PointCut)、增强(Advice)。

cacheAdvisor():注册advisor BeanFactoryCacheOperationSourceAdvisor,并调用 cacheOperationSource() 和 cacheInterceptor() 设置切点和增强。

cacheOperationSource():注册切点,类型就是 AnnotationCacheOperationSource实现了CacheOperationSource接口。

24 行:创建的时候干了一些事情(见图1):

  1. 设置本类属性 boolean publicMethodsOnly 为 true(后面会用到)。
  2. 设置本类属性 Set annotationParsers 为 Collections.singleton(new SpringCacheAnnotationParser()),SpringCacheAnnotationParser 类就是用来解析方法上是否有缓存注解的,静态属性设置了注解操作信息。

image.png

cacheInterceptor():注册增强 CacheInterceptor(缓存操作就在这里面了)。
31 行:创建一个CacheInterceptor 对象。 32 行:进行一些初始化设置

  • errorHandler = SimpleCacheErrorHandler
  • keyGenerator = SimpleKeyGenerator
  • cacheResolver = SimpleCacheResolver

33 行:设置缓存操作源,和上面设置切点一样

public abstract class CacheAspectSupport extends AbstractCacheInvoker
		implements BeanFactoryAware, InitializingBean, SmartInitializingSingleton {

	protected final Log logger = LogFactory.getLog(getClass());

	private final Map<CacheOperationCacheKey, CacheOperationMetadata> metadataCache = new ConcurrentHashMap<>(1024);

	private final CacheOperationExpressionEvaluator evaluator = new CacheOperationExpressionEvaluator();

	@Nullable
	private CacheOperationSource cacheOperationSource;

	private SingletonSupplier<KeyGenerator> keyGenerator = SingletonSupplier.of(SimpleKeyGenerator::new);

	@Nullable
	private SingletonSupplier<CacheResolver> cacheResolver;

	@Nullable
	private BeanFactory beanFactory;

	private boolean initialized = false;


	/**
	 * Configure this aspect with the given error handler, key generator and cache resolver/manager
	 * suppliers, applying the corresponding default if a supplier is not resolvable.
	 * @since 5.1
	 */
	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)));
	}
	/**
	 * Set the CacheOperationSource for this cache aspect.
	 * @since 5.1
	 * @see #setCacheOperationSources
	 */
	public void setCacheOperationSource(@Nullable CacheOperationSource cacheOperationSource) {
		this.cacheOperationSource = cacheOperationSource;
	}
}

CacheInterceptor

image.png

CacheInterceptor 实现了 SmartInitializingSingleton 接口,实现该接口的类在bean实例化之后会调用afterSingletonsInstantiated()

@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.");
        }
        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.");
        }
    }
    this.initialized = true;
}

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

7 行:设置CacheManager。从IOC容器中获取到CacheManager,然后作为入参创建SimpleCacheResolver 并赋值给本类的cacheResolver属性。

业务类

// 配置类
@Configuration
@EnableCaching
public static class Spr11124Config {
    // 注入 CacheManager
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager();
    }

    // 注入业务类TestService
    @Bean
    public TestService service() {
        return new TestServiceImpl();
    }
}
// 业务接口
public interface TestService {
    int single(int id);
}
// 业务实现类
public static class TestServiceImpl implements TestService {

    @Override
    @Cacheable("smallCache")
    public int single(int id) {
        System.out.println("执行逻辑。。。");
        return id;
    }
}

@Test
public void spr11124MultipleAnnotations2() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11124Config.class);

    TestService bean = context.getBean(TestService.class);
    System.out.println(bean.single(2));
    System.out.println(bean.single(2));
    context.close();
}

bean实例化之后会进入aop创建代理逻辑,通过IOC中所有的Advisor 的 切点进行匹配,如果当前bean匹配成功,就会创建代理。
业务类 TestServiceImpl 在实例化之后,在进行Advisor匹配时,会被上面创建的BeanFactoryCacheOperationSourceAdvisor匹配到。匹配流程如下:

这一块属于Aop源码,这里不详细说明,只列出大致逻辑。

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    Assert.notNull(pc, "Pointcut must not be null");
    //调用ClassFilter的matches方法,判断类是否匹配
    //通过AspectJ 类级别过滤
    if (!pc.getClassFilter().matches(targetClass)) {
        return false;
    }
    //方法级别过滤,精筛
    MethodMatcher methodMatcher = pc.getMethodMatcher();
    if (methodMatcher == MethodMatcher.TRUE) {
        // No need to iterate the methods if we're matching any method anyway...
        return true;
    }

    IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
    //		只有AspectJExcpressionPointcut才会实现这个接口
    if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
        introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
    }
    //		保存 tagetClass  的 class对象
    Set<Class<?>> classes = new LinkedHashSet<>();
    //		判断当前class是不是代理的class
    if (!Proxy.isProxyClass(targetClass)) {
        classes.add(ClassUtils.getUserClass(targetClass));
    }
    //		获取到当前class实现的接口 的  class对象(@AspectJ 注解没有,事务有用)
    classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

    //判断类中方法是否匹配,,有些可能是方法上面有注解的拦截,所以需要判断方法是否匹配
    //		循环所有的class
    for (Class<?> clazz : classes) {
        // 找出class中所有的方法
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        for (Method method : methods) {
            if (introductionAwareMethodMatcher != null ?
                //	通过切点表达式进行匹配 AspectJ 方式
                introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                //	通过方法匹配器进行匹配,内置aop接口方式
                methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }

    return false;
}

37 行:调用Advisor.Pointcut#matches(),如下代码:

public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

	// 切点 AnnotationCacheOperationSource
	@Nullable
	private CacheOperationSource cacheOperationSource;

	// 增强 CacheInterceptor
	private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
		@Override
		@Nullable
		protected CacheOperationSource getCacheOperationSource() {
			return cacheOperationSource;
		}
	};
    ...
}

8 行: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();
		return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)));
	}
    ...
        
	@Nullable
	protected abstract CacheOperationSource getCacheOperationSource();

    ...

}

9 行:matches() 就是具体匹配切点的逻辑。

10 行:首先获取CacheOperationSource,转调getCacheOperationSource(),这个方法是个抽象方法,具体实现在上面 BeanFactoryCacheOperationSourceAdvisor.pointcut 属性赋值的地方,最终返回的是BeanFactoryCacheOperationSourceAdvisor.cacheOperationSource属性的值,这个属性在上面讲实例化该bean的时候就已经赋值了--AnnotationCacheOperationSource

11 行:然后再调用AnnotationCacheOperationSource.getCacheOperations(),这个方法是父类AbstractFallbackCacheOperationSource的方法,如下代码:

public abstract class AbstractFallbackCacheOperationSource implements CacheOperationSource {

	private static final Collection<CacheOperation> NULL_CACHING_ATTRIBUTE = Collections.emptyList();
	protected final Log logger = LogFactory.getLog(getClass());
    // CacheOperation 缓存
	private final Map<Object, Collection<CacheOperation>> attributeCache = 
        new ConcurrentHashMap<>(1024);


	/**
	 * Determine the caching attribute for this method invocation.
	 * <p>Defaults to the class's caching attribute if no method attribute is found.
	 * @param method the method for the current invocation (never {@code null})
	 * @param targetClass the target class for this invocation (may be {@code null})
	 * @return {@link CacheOperation} for this method, or {@code null} if the method
	 * is not cacheable
	 */
	@Override
	@Nullable
	public Collection<CacheOperation> getCacheOperations(Method method, @Nullable Class<?> targetClass) {
		if (method.getDeclaringClass() == Object.class) {
			return null;
		}
		// 根据方法和目标类 生成缓存key
		Object cacheKey = getCacheKey(method, targetClass);
		// 先从缓存获取
		Collection<CacheOperation> cached = this.attributeCache.get(cacheKey);

		if (cached != null) {
			return (cached != NULL_CACHING_ATTRIBUTE ? cached : null);
		}
		else {
			// 找出方法的缓存注解并生成CacheOperation,一个注解对应一个CacheOperation
			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;
		}
	}
    // 生成缓存key
	protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) {
		return new MethodClassKey(method, targetClass);
	}

	@Nullable
	private Collection<CacheOperation> computeCacheOperations(Method method, @Nullable Class<?> targetClass) {
		// Don't allow no-public methods as required.
		// 方法不是public 修饰的,直接返回null
		// allowPublicMethodsOnly() 默认为FALSE,AnnoXXX重写方法为true
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		// 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;
	}
    // 抽象方法 被 AnnotationCacheOperationSource 实现
    @Nullable
	protected abstract Collection<CacheOperation> findCacheOperations(Method method);
    
    // 被 AnnotationCacheOperationSource 重写,返回为true
    protected boolean allowPublicMethodsOnly() {
		return false;
	}

    ...

}

21 行:如果是Object类的方法就跳过。
25 行:根据类和方法生成一个Key值。
27 行:先从缓存中获取。
34 行:第一次拿不到走生成逻辑,转调 computeCacheOperations() 整个方法尝试好几次调用findCacheOperations()获取CacheOperation ,findCacheOperations() 是抽象方法,被 AnnotationCacheOperationSource 实现,代码如下:

public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implements Serializable {
    private final boolean publicMethodsOnly;
	private final Set<CacheAnnotationParser> annotationParsers;   
    
    @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));
	}
    
}

转调 SpringCacheAnnotationParser.parseCacheAnnotations(),这个类上面提到过。代码如下:

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) {
		DefaultCacheConfig defaultConfig = new DefaultCacheConfig(type);
		return parseCacheAnnotations(defaultConfig, type);
	}

	@Override
	@Nullable
	public Collection<CacheOperation> parseCacheAnnotations(Method method) {
		DefaultCacheConfig defaultConfig = new DefaultCacheConfig(method.getDeclaringClass());
		return parseCacheAnnotations(defaultConfig, method);
	}

	@Nullable
	private Collection<CacheOperation> parseCacheAnnotations(DefaultCacheConfig cachingConfig, AnnotatedElement ae) {
		// 解析缓存注解
		// 把方法上面的缓存注解找出来 生成CacheOperation
		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) {
		// 获取方法所有注解
		Collection<? extends Annotation> anns = (localOnly ?
				AnnotatedElementUtils.getAllMergedAnnotations(ae, CACHE_OPERATION_ANNOTATIONS) :
				AnnotatedElementUtils.findAllMergedAnnotations(ae, CACHE_OPERATION_ANNOTATIONS));
		if (anns.isEmpty()) {
			return null;
		}
		// 如果是缓存的注解,生成CacheOperation
		final Collection<CacheOperation> ops = new ArrayList<>(1);
		anns.stream().filter(ann -> ann instanceof Cacheable).forEach(
				ann -> ops.add(parseCacheableAnnotation(ae, cachingConfig, (Cacheable) ann)));
		anns.stream().filter(ann -> ann instanceof CacheEvict).forEach(
				ann -> ops.add(parseEvictAnnotation(ae, cachingConfig, (CacheEvict) ann)));
		anns.stream().filter(ann -> ann instanceof CachePut).forEach(
				ann -> ops.add(parsePutAnnotation(ae, cachingConfig, (CachePut) ann)));
		anns.stream().filter(ann -> ann instanceof Caching).forEach(
				ann -> parseCachingAnnotation(ae, cachingConfig, (Caching) ann, ops));
		return ops;
	}
    
    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;
	}
}

parseCacheAnnotations()有4个重载,最终会调用到parseCacheAnnotations(DefaultCacheConfig cachingConfig, AnnotatedElement ae, boolean localOnly)
51 行:获取方法上面的注解。
58~67 行:判断这些注解是不是缓存注解,如果是,就调用对应方法创建CacheableOperation并返回。 这个地方如果返回CacheableOperation不为空,那就是切点匹配到了,先将CacheableOperation放入缓存,然后再给bean创建代理。

缓存流程

缓存需要的bean都已经注册到IOC容器了,此时IOC容器中存储的是业务类的代理类,当调用业务类的方法时,会被advisor(BeanFactoryCacheOperationSourceAdvisor)拦截,最终会调用到BeanFactoryCacheOperationSourceAdvisor 的增强也就是 CacheInterceptor 中,

// 配置类
@Configuration
@EnableCaching
public static class Spr11124Config {
    // 注入 CacheManager
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager();
    }

    // 注入业务类TestService
    @Bean
    public TestService service() {
        return new TestServiceImpl();
    }
}
// 业务接口
public interface TestService {
    int single(int id);
}
// 业务实现类
public static class TestServiceImpl implements TestService {

    @Override
    @Cacheable("smallCache")
    public int single(int id) {
        System.out.println("执行逻辑。。。");
        return id;
    }
}

@Test
public void spr11124MultipleAnnotations2() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11124Config.class);

    TestService bean = context.getBean(TestService.class);
    System.out.println(bean.single(2));
    System.out.println(bean.single(2));
    context.close();
}
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor {

	@Override
	@Nullable
	public Object invoke(final MethodInvocation invocation) throws Throwable {
		Method method = invocation.getMethod();

		CacheOperationInvoker aopAllianceInvoker = () -> {
			try {
				return invocation.proceed();
			}
			catch (Throwable ex) {
				throw new CacheOperationInvoker.ThrowableWrapper(ex);
			}
		};

		try {
			// 执行缓存操作
			return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments());
		}
		catch (CacheOperationInvoker.ThrowableWrapper th) {
			throw th.getOriginal();
		}
	}

}
@Nullable
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
    // Check whether aspect is enabled (to cope with cases where the AJ is pulled in automatically)
    if (this.initialized) {
        Class<?> targetClass = getTargetClass(target);
        // 缓存操作源 AnnotationCacheOperationSource
        CacheOperationSource cacheOperationSource = getCacheOperationSource();
        if (cacheOperationSource != null) {
            // 获取当前方法缓存注解信息,缓存操作对象CacheOperation 存储了缓存注解的信息
            Collection<CacheOperation> operations = cacheOperationSource.getCacheOperations(method, targetClass);
            if (!CollectionUtils.isEmpty(operations)) {
                return execute(invoker, method,
                               new CacheOperationContexts(operations, method, args, target, targetClass));
            }
        }
    }

    return invoker.invoke();
}

7 行: 缓存操作源-->AnnotationCacheOperationSource

10 行:获取缓存操作源CacheOperationSource,getCacheOperations() 上面Advisor匹配方法创建代理的时候就是用的这个方法,当时已经获取到了所有方法的CacheOperationSource并且存储到了名为attributeCache 的缓存中,现在直接从缓存获取即可。

13 行:创建缓存上下文对象,包含了从缓存获取数据的逻辑。代码如下:

private class CacheOperationContexts {
    // <类, CacheOperationContext>
    // CacheOperationContext 封装了注解的信息  以及缓存值
    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(),
                              // 创建CacheOperationContext
                              getOperationContext(op, method, args, target, targetClass));
        }
        this.sync = determineSyncFlag(method);
    }
}

protected CacheOperationContext getOperationContext(
			CacheOperation operation, Method method, Object[] args, Object target, Class<?> targetClass) {
    // 缓存注解信息
    CacheOperationMetadata metadata = getCacheOperationMetadata(operation, method, targetClass);
    // 生成CacheOperationContext
    //
    return new CacheOperationContext(metadata, args, target);
}

protected class CacheOperationContext implements CacheOperationInvocationContext<CacheOperation> {

    private final CacheOperationMetadata metadata;

    private final Object[] args;

    private final Object target;

    private final Collection<? extends Cache> caches;

    private final Collection<String> cacheNames;

    @Nullable
    private Boolean conditionPassing;

    public CacheOperationContext(CacheOperationMetadata metadata, Object[] args, Object target) {
        this.metadata = metadata;
        this.args = extractArgs(metadata.method, args);
        this.target = target;
        // 获取缓存
        this.caches = CacheAspectSupport.this.getCaches(this, metadata.cacheResolver);
        this.cacheNames = createCacheNames(this.caches);
    }
}
/**
	 * 获取缓存
	 *
	 * @param context       上下文
	 * @param cacheResolver 缓存解析器  SimpleCacheResolver
	 * @return {@link Collection}<{@link ?} {@link extends} {@link Cache}>
	 */
protected Collection<? extends Cache> getCaches(
    CacheOperationInvocationContext<CacheOperation> context, CacheResolver cacheResolver) {
    // 缓存加载器 获取缓存对象
    Collection<? extends Cache> caches = cacheResolver.resolveCaches(context);
    if (caches.isEmpty()) {
        throw new IllegalStateException("No cache could be resolved for '" +
                                        context.getOperation() + "' using resolver '" + cacheResolver +
                                        "'. At least one cache should be provided per cache operation.");
    }
    return caches;
}

12 行:给每一个CacheOperation创建一个上下文对象
17 行:创建上下文对象
29 行:执行创建上下文对象
47 行:构造方法,可以看出,上下文对象存储了方法的注解信息、方法参数、类信息、缓存值,缓存名称
52 行:获取缓存值,转掉本类方法getCaches()
66 行:转调cacheResolver.resolveCaches(context) ,代码如下:

public abstract class AbstractCacheResolver implements CacheResolver, InitializingBean {

	@Nullable
	private CacheManager cacheManager;
    
    public CacheManager getCacheManager() {
		Assert.state(this.cacheManager != null, "No CacheManager set");
		return this.cacheManager;
	}
    
    @Override
	public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
		// 获取到缓存名称
		Collection<String> cacheNames = getCacheNames(context);
		if (cacheNames == null) {
			return Collections.emptyList();
		}
		// 缓存结果
		Collection<Cache> result = new ArrayList<>(cacheNames.size());
		for (String cacheName : cacheNames) {
			// 从缓存管理器中获取缓存对象
			Cache cache = getCacheManager().getCache(cacheName);
			if (cache == null) {
				throw new IllegalArgumentException("Cannot find cache named '" +
						cacheName + "' for " + context.getOperation());
			}
			result.add(cache);
		}
		return result;
	}
}

14 行:首选拿到缓存名
20 行:循环缓存名,去缓存管理器CacheManager获取缓存值,这个CacheManager就是我们向容器中注入的 ConcurrentMapCacheManager,那就会转调到ConcurrentMapCacheManager.getCache(),代码如下:

public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware {
    // <缓存名,缓存值>
	private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
    
    @Override
	@Nullable
	public Cache getCache(String name) {
		Cache cache = this.cacheMap.get(name);
		if (cache == null && this.dynamic) {
			synchronized (this.cacheMap) {
				cache = this.cacheMap.get(name);
				if (cache == null) {
					cache = createConcurrentMapCache(name);
					this.cacheMap.put(name, cache);
				}
			}
		}
		return cache;
	}
    protected Cache createConcurrentMapCache(String name) {
		SerializationDelegate actualSerialization = (isStoreByValue() ? this.serialization : null);
		return new ConcurrentMapCache(name, new ConcurrentHashMap<>(256), isAllowNullValues(), actualSerialization);
	}   
}

这个逻辑就比较简单了,先根据缓存名称去缓存Map中查找缓存对象,没找到就创建一个放入缓存Map中,这里的缓存对象是ConcurrentMapCache,然后一路返回到CacheAspectSupport#execute()

@Nullable
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
    // Check whether aspect is enabled (to cope with cases where the AJ is pulled in automatically)
    if (this.initialized) {
        Class<?> targetClass = getTargetClass(target);
        // 缓存操作源 AnnotationCacheOperationSource
        CacheOperationSource cacheOperationSource = getCacheOperationSource();
        if (cacheOperationSource != null) {
            // 获取当前方法缓存注解信息,缓存操作对象CacheOperation 存储了缓存注解的信息
            Collection<CacheOperation> operations = cacheOperationSource.getCacheOperations(method, targetClass);
            if (!CollectionUtils.isEmpty(operations)) {
                return execute(invoker, method,
                               new CacheOperationContexts(operations, method, args, target, targetClass));
            }
        }
    }

    return invoker.invoke();
}

那现在13 行已经走完了,走12 行转调 本类 execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts)

@Nullable
private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
    // Special handling of synchronized invocation
    // 同步调用的特殊处理 线程安全处理
    if (contexts.isSynchronized()) {
        // 拿到缓存上下文对象
        CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();
        if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
            Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
            Cache cache = context.getCaches().iterator().next();
            try {
                return wrapCacheValue(method, cache.get(key, () -> unwrapReturnValue(invokeOperation(invoker))));
            }
            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);
        }
    }


    //先处理@CacheEvicts的逻辑,,其实就是掉clear方法
    // Process any early evictions
    processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
                       CacheOperationExpressionEvaluator.NO_RESULT);

    //处理@Cacheable的逻辑,其实就是掉get方法
    // Check if we have a cached item matching the conditions
    // cacheHit 就是缓存对象对应的值,也就是缓存的值
    Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));

    // Collect puts from any @Cacheable miss, if no cached item is found
    // 存储没有命中缓存的 CacheableOperation 并封装成 CachePutRequest 对象
    List<CachePutRequest> cachePutRequests = new LinkedList<>();
    //如果缓存没命中或者不是使用的@Cacheable注解
    if (cacheHit == null) {
        //处理@Cacheable的逻辑,收集插入请求,插入缓存的值需要调用被代理方法
        collectPutRequests(contexts.get(CacheableOperation.class),
                           CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
    }

    // 缓存值
    Object cacheValue;
    // 本方法返回的值
    Object returnValue;

    //如果缓存命中了
    if (cacheHit != null && !hasCachePut(contexts)) {
        // If there are no put requests, just use the cache hit
        cacheValue = cacheHit.get();
        //直接返回缓存中的值
        returnValue = wrapCacheValue(method, cacheValue);
    }
    else {
        //在这里调用被代理方法
        // Invoke the method if we don't have a cache hit
        returnValue = invokeOperation(invoker);
        cacheValue = unwrapReturnValue(returnValue);
    }

    // 处理@CachePut注解,收集put请求
    // Collect any explicit @CachePuts
    collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);

    //处理put请求,其实就是掉put方法
    // Process any collected put requests, either from @CachePut or a @Cacheable miss
    for (CachePutRequest cachePutRequest : cachePutRequests) {
        cachePutRequest.apply(cacheValue);
    }

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

    return returnValue;
}

这个方法干了什么事情呢?

  1. 处理各个注解
  2. 如果缓存没有命中就调用原方法获取返回值并放入缓存Map中

总结

这就是sprng-cache 整体的逻辑,可以看到,sprng-cache可以看做是一个通用的缓存规范框架,真正操作缓存的就是cachemanager 和 cache 这两个类,而这两个类又是需要开发者自己定义的,例子中使用的是ConcurrentMapCacheManager 和 ConcurrentMapCache , spring本身也提供了别的,如下图: image.png 使用哪个只需要注入到容器即可。

注:本文通过源码 + 行说明的方式进行描述,若不好理解可留言。本文仅为个人学习记录,有错误的地方,请大佬们指正。