spring-cache源码解析

本文写作时间2024-09-29 10:41:01


重学SpringBoot系列之Spring cache详解

哔站springcache源码解析

源码解析 配合上面的视频查看

  • 源码下载:

github spring源码

源码下载说明

  • 扩展知识

spring advisor aop

源码解析

springcache 利用 spring aop实现的缓存框架

常用的 启动注解 三个注解 以及组合注解 和 公共注解。

缓存的初始化过程

项目如果需要缓存支持,需要使用注解 @org.springframework.cache.annotation.EnableCaching
添加该注解后,会导入 CachingConfigurationSelector

@Import(CachingConfigurationSelector.class)
public @interface EnableCaching 

CachingConfigurationSelector类实现了 ImportSelector 接口,根据EnableCaching.mode,来导入相应的类,这里以默认的PROXY为例说明,会导入配置类ProxyCachingConfiguration

public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
	@Override
	public String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return getProxyImports();
			case ASPECTJ:
				return getAspectJImports();
			default:
				return null;
		}
	}
	private String[] getProxyImports() {
		List<String> result = new ArrayList<>(3);
		result.add(AutoProxyRegistrar.class.getName());
		result.add(ProxyCachingConfiguration.class.getName());
		if (jsr107Present && jcacheImplPresent) {
			result.add(PROXY_JCACHE_CONFIGURATION_CLASS);
		}
		return StringUtils.toStringArray(result);
	}

ProxyCachingConfiguration类定义了3个Bean:

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {
	@Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor() {
		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() {
		return new AnnotationCacheOperationSource();
	}

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

同时,ProxyCachingConfiguration的父类AbstractCachingConfiguration,会加载自定义配置:

@Autowired(required = false)
void setConfigurers(Collection<CachingConfigurer> configurers) {
	if (CollectionUtils.isEmpty(configurers)) {
		return;
	}
	if (configurers.size() > 1) {
		throw new IllegalStateException(...);
	}
	CachingConfigurer configurer = configurers.iterator().next();
	useCachingConfigurer(configurer);
}

这里可以通过 实现 CachingConfigurer接口,来自定义CacheManager和CacheResolver等对象,
上面的Bean CacheInterceptor对象属性初始值,就是读取这里返回的对象:

ProxyCachingConfiguration 类里面的 BeanFactoryCacheOperationSourceAdvisor实例,继承了Advisor接口,在获取后续的Bean时,会对这些Bean Bean.getDeclaredMethods方法清单里的每个方法,调用matches进行检测:

此处即是aop的织入

// BeanFactoryCacheOperationSourceAdvisor的private属性CacheOperationSourcePointcut 里的方法
@Override
public boolean matches(Method method, Class<?> targetClass) {
	CacheOperationSource cas = getCacheOperationSource();
	return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)));
}

这个cas就是ProxyCachingConfiguration里的AnnotationCacheOperationSource实例,通过cas.getCacheOperations方法,
调用org.springframework.cache.annotation.SpringCacheAnnotationParser类的方法parseCacheAnnotations,
读取Bean的方法上的Cacheable、CacheEvict、CachePut、Caching这4个注解定义,并转成 CacheOperation,然后缓存起来.
如果发现该Bean的方法存在上述4个注解定义时,会对该类套一层缓存代理,每次调用缓存方法,都会被 BeanFactoryCacheOperationSourceAdvisor.getAdvice()所拦截,这个getAdvice方法返回的就是上面ProxyCachingConfiguration里的CacheInterceptor实例

Bean初始化完成后,会调用 CacheInterceptor.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;
}

这段代码里,设置了CacheInterceptor实例的cacheResolver属性:

  • 如果有CachingConfigurer定义的CacheResolver且不为空,则使用该CacheResolver里定义的Cache;
  • 如果有CachingConfigurer定义的CacheManager且不为空,则使用该CacheManager;
  • 如果CacheResolver为空,则从Bean工厂去获取CacheManager的Bean,并设置为new SimpleCacheResolver(cacheManager)。

到这里,缓存的初始化加载工作基本完成了,下面是具体的缓存方法调用过程。

缓存方法执行过程:

那我们实际调用方法的时候,是怎么处理的呢?我们知道,使用了AOPBean,会生成一个代理对象,实际调用的时候,会执行这个代理对象的一系列的InterceptorSpring Cache使用的是一个叫做CacheInterceptor的拦截器。我们如果加了缓存相应的注解,就会走到这个拦截器上。这个拦截器继承了CacheAspectSupport类,会执行这个类的execute方法,这个方法就是我们要分析的核心方法了。

1、调用缓存方法时,会先调用 CacheInterceptor.invoke => CacheAspectSupport.execute => AnnotationCacheOperationSource.getCacheOperations
对,就是上面缓存起来的4个Cache注解定义得到的CacheOperation.

2、然后会新建 new CacheOperationContexts,在这个CacheOperationContexts的构造函数里,会依次判断并获得最终要使用的CacheResolver:

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);
	operationCacheResolver = new SimpleCacheResolver(cacheManager);
}
else {  
    // 使用CacheInterceptor实例的cacheResolver
	operationCacheResolver = getCacheResolver();
	Assert.state(operationCacheResolver != null, "No CacheResolver/CacheManager set");
}

得到 CacheResolver后,再调用CacheResolver.resolveCaches,得到当前方法依赖的Cache列表,其内部就是调用cacheManager.getCache,参数为:注解的cacheNames属性。
构造函数最后再收集最终要使用的cacheNames集合。

3、接着再进入CacheAspectSupport实例的另一个重载:
private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts)
在这个重载方法里,依次处理缓存逻辑:

// 方法调用前的缓存过期处理,设置了CacheEvict.isBeforeInvocation属性时
processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
		CacheOperationExpressionEvaluator.NO_RESULT);

// Cacheable注解时,去查找缓存
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));

// 缓存未命中时,把Cacheable加入到CachePut的集合,后面用于写入缓存
List<CachePutRequest> cachePutRequests = new LinkedList<>();
if (cacheHit == null) {
	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 {
	// 未找到缓存时,调用目标方法
	returnValue = invokeOperation(invoker);
	cacheValue = unwrapReturnValue(returnValue);
}

// 收集CachePut注解,后面写入缓存
collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);

// 写入缓存
for (CachePutRequest cachePutRequest : cachePutRequests) {
	cachePutRequest.apply(cacheValue);
}

// 处理缓存过期逻辑
processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);
// 返回结果给代理类
return returnValue;

4、整个源码过程如上,没有解读keyGenerator,它跟cacheResolver的过程差不多。
还有就是具体的读取、设置缓存细节也没有描述。

补充

主要涉及切面编程问题; 至于其他的cachemanage 留后查看