简介
本章内容基础读者了解springcache的基本使用的情况下进行编写,如有读者对springcache基本使用不了解的话,请点击SpringCache使用
@EnableCaching注解原理
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
//是否开启cglib代理
boolean proxyTargetClass() default false;
//代理模式,PROXY=代理,ASPECT=
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
spring使用@EnableCaching注解来启用springcache功能,在EnableCaching中有以上几个参数,以及核心类CachingConfigurationSelector
参数说明:
| 参数 | 说明 |
|---|---|
| proxyTargetClass | 是否使用cglib代理,默认false |
| mode | 代理方式(PROXY(代理模式)、ASPECT(切面模式)) |
| order | 多个代理器同时在一个类上作用时,该代理器的顺序 |
CachingConfigurationSelector介绍
该类在被@Import注解注释,表明CachingConfigurationSelector是一个配置类,spring会调用CachingConfigurationSelector中的selectImports方法来实例化查询出来的类,接下来以PROXY代理方式来介绍源码
public String[] selectImports(AdviceMode adviceMode) {
return switch (adviceMode) {
case PROXY -> getProxyImports();
case ASPECTJ -> getAspectJImports();
};
}
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);
}
在getProxyImports返回了AutoProxyRegistrar跟ProxyCachingConfiguration类名,代表了spring会对着2个类进行实例化,接下来我们来看一下这2个类具体做了什么。
AutoProxyRegistrar介绍
该类主要实现了注册aop所需要的核心bean,启用aop代理功能的核心类,比如开启事务注解也会注册这个类
ProxyCachingConfiguration介绍
ProxyCachingConfiguration类内容介绍
该类是SpringCache中一个核心类,其主要功能就是给把原始spring对象封装成SpringCache代理对象,让其方法可被SpringCache框架拦截从而实现缓存逻辑。里面做了3件事
- 初始化CacheOperationSource(用于根据类+方法获取方法上缓存注解的一些信息)
- 初始化CacheInterceptor,设置errorHandler(错误处理器), keyGenerator(key生成器), this.cacheResolver(缓存处理器), this.cacheManager(缓存实现方法)到CacheInterceptor,设置CacheOperationSource到CacheInterceptor中
- 初始化BeanFactoryCacheOperationSourceAdvisor对象,设置cacheOperationSource跟cacheInterceptor,用户spring注册bean的时候使用
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cache.annotation;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.cache.config.CacheManagementConfigUtils;
import org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor;
import org.springframework.cache.interceptor.CacheInterceptor;
import org.springframework.cache.interceptor.CacheOperationSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
/**
* {@code @Configuration} class that registers the Spring infrastructure beans necessary
* to enable proxy-based annotation-driven cache management.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see EnableCaching
* @see CachingConfigurationSelector
*/
@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();
//1.设置缓存操作类
advisor.setCacheOperationSource(cacheOperationSource);
//2.设置aop拦截器
advisor.setAdvice(cacheInterceptor);
if (this.enableCaching != null) {
advisor.setOrder(this.enableCaching.<Integer>getNumber("order"));
}
return advisor;
}
/**
* spring操作方法获取类,通过方法+类获取类上的注解
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public CacheOperationSource cacheOperationSource() {
// Accept protected @Cacheable etc methods on CGLIB proxies, as of 6.0.
return new AnnotationCacheOperationSource(false);
}
/**
* 拦截器
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public CacheInterceptor cacheInterceptor(CacheOperationSource cacheOperationSource) {
CacheInterceptor interceptor = new CacheInterceptor();
interceptor.configure(this.errorHandler, this.keyGenerator, this.cacheResolver, this.cacheManager);
interceptor.setCacheOperationSource(cacheOperationSource);
return interceptor;
}
}
ProxyCachingConfiguration注解逻辑介绍
在springbean初始化过程中该对象在org.springframework.cache.config.AnnotationDrivenCacheBeanDefinitionParser.SpringCachingConfigurer#registerCacheAdvisor中被获取以及初始化成BeanDefinition,然后随着spring一系列流程被初始化成spring的bean对象
@CacheInterceptor springcache方法拦截器介绍
该类是aop中的拦截器,主要作用是重写invoke方法实现调用方法先走缓存,再调用被代理方法
@CacheInterceptor继承图
@CacheInterceptor执行逻辑说明
CacheInterceptor中invoke方法中主要逻辑实现在CacheAspectSupport的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();
}
}
}
CacheAspectSupport对象的execute方法说明
@Nullable
private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
//判断方法上的注解使用启用了sync
if (contexts.isSynchronized()) {
//获取缓存操作对象上下文
CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();
//满足condition条件
if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
//生成缓存key
Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
//获取公共缓存操作方法接口
Cache cache = context.getCaches().iterator().next();
try {
//执行方法业务方法获取返回值
return wrapCacheValue(method, handleSynchronizedGet(invoker, key, cache));
}
catch (Cache.ValueRetrievalException ex) {
// Directly propagate ThrowableWrapper from the invoker,
// or potentially also an IllegalArgumentException etc.
ReflectionUtils.rethrowRuntimeException(ex.getCause());
}
}
else {
// No caching required, only call the underlying method
return invokeOperation(invoker);
}
}
// 执行@CacheEvict注解的内容来使缓存失效
processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
CacheOperationExpressionEvaluator.NO_RESULT);
// 获取命中的缓存
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
// 处理@CachePut
List<CachePutRequest> cachePutRequests = new ArrayList<>();
if (cacheHit == null) {
//手机需要更新的缓存操作到cachePutRequests
collectPutRequests(contexts.get(CacheableOperation.class),
CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
}
Object cacheValue;
Object returnValue;
if (cacheHit != null && !hasCachePut(contexts)) {
// 如果没有put请求,就使用缓存命中
cacheValue = cacheHit.get();
returnValue = wrapCacheValue(method, cacheValue);
}
else {
// 如果没有查询到缓存,就执行方法来获取结果
returnValue = invokeOperation(invoker);
cacheValue = unwrapReturnValue(returnValue);
}
// 再次获取需要处理的更新缓存操作,@CachePut,因为注解中有unless字段,需要根据返回值来判断是否满足
collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);
// Process any collected put requests, either from @CachePut or a @Cacheable miss
//执行缓存更新的操作
for (CachePutRequest cachePutRequest : cachePutRequests) {
cachePutRequest.apply(cacheValue);
}
// 执行缓存失效的操作,由于unless字段需要重复执行该动作
processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);
return returnValue;
}
processCacheEvicts方法简介
private void processCacheEvicts(
Collection<CacheOperationContext> contexts, boolean beforeInvocation, @Nullable Object result) {
//遍历所有的缓存失效操作对象上下文
for (CacheOperationContext context : contexts) {
CacheEvictOperation operation = (CacheEvictOperation) context.metadata.operation;
//满足缓存失效条件
if (beforeInvocation == operation.isBeforeInvocation() && isConditionPassing(context, result)) {
//进行缓存失效操作
performCacheEvict(context, operation, result);
}
}
}
private void performCacheEvict(
CacheOperationContext context, CacheEvictOperation operation, @Nullable Object result) {
Object key = null;
//循环方法对应的所有缓存失效的缓存器
for (Cache cache : context.getCaches()) {
//
if (operation.isCacheWide()) {
logInvalidating(context, operation, null);
doClear(cache, operation.isBeforeInvocation());
}
else {
if (key == null) {
//获取key
key = generateKey(context, result);
}
//记录日志
logInvalidating(context, operation, key);
//执行缓存失效方法
doEvict(cache, key, operation.isBeforeInvocation());
}
}
}
protected void doEvict(Cache cache, Object key, boolean immediate) {
try {
if (immediate) {
//立即执行缓存失效
cache.evictIfPresent(key);
}
else {
//可能是异步调用,有可能会延迟
//调用缓存失效方法接口,按照具体实现类执行对应方法
cache.evict(key);
}
}
catch (RuntimeException ex) {
getErrorHandler().handleCacheEvictError(ex, cache, key);
}
}
collectPutRequests方法简介
private void collectPutRequests(Collection<CacheOperationContext> contexts,
@Nullable Object result, Collection<CachePutRequest> putRequests) {
for (CacheOperationContext context : contexts) {
//判断condition是否满足条件
if (isConditionPassing(context, result)) {
//根据key生成器生成key
Object key = generateKey(context, result);
//将CachePutRequest对象放到putRequests中
putRequests.add(new CachePutRequest(context, key));
}
}
}
protected boolean isConditionPassing(@Nullable Object result) {
if (this.conditionPassing == null) {
if (StringUtils.hasText(this.metadata.operation.getCondition())) {
EvaluationContext evaluationContext = createEvaluationContext(result);
this.conditionPassing = evaluator.condition(this.metadata.operation.getCondition(),
this.metadata.methodKey, evaluationContext);
}
else {
this.conditionPassing = true;
}
}
return this.conditionPassing;
}
CachePutRequest.apply()方法简介
public void apply(@Nullable Object result) {
//调用canPutToCache判断是否需要执行动作,主要是unless字段条件的判断,
if (this.context.canPutToCache(result)) {
//获取方法对应所有的缓存器Cache对象集合
for (Cache cache : this.context.getCaches()) {
//调用接口Cache的put方法根据具体的实现方法来设置缓存
doPut(cache, this.key, result);
}
}
}
protected void doPut(Cache cache, Object key, @Nullable Object result) {
try {
//调用接口Cache的put方法根据具体的实现方法来设置缓存
cache.put(key, result);
}
catch (RuntimeException ex) {
getErrorHandler().handleCachePutError(ex, cache, key, result);
}
}
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();
}
if (StringUtils.hasText(unless)) {
EvaluationContext evaluationContext = createEvaluationContext(value);
return !evaluator.unless(unless, this.metadata.methodKey, evaluationContext);
}
return true;
}