【Spring Cache】三 CacheOperationInvocationContext CacheOperationExpressionEvaluator

【Spring Cache】三 CacheOperationInvocationContext CacheOperationExpressionEvaluator

前言

之前的章节了解到 缓存操作注解 的属性 CacheResolver 时,提到它解析对应的 Cache 是基于 CacheOperationInvocationContext 的,因此本章节再深入了解下 CacheOperationInvocationContext ,同时了解下缓存注解支持 SpEL 表达式相关的 CacheOperationExpressionEvaluator

SpEL

Spring Expression LanguageCache 相关注解的属性诸如 key condition unless 都支持 SpEL 的解析,关于 SpEL 可以参考以下文章或者跳过直接看 demo 大体回顾下

【Spring】SpEL 一 语法总结与示例

【Spring】SpEL 二 PropertyAccessor 相关(BeanFactoryAccessor EnvironmentAccessor)

demo

public class SpELDemo {

    @Configuration
    public static class Config {

        @Bean
        public A a() {
            return new A("bean");
        }
    }

    public static class A {

        private String name;

        public A(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    @Test
    public void test() {
        ConfigurableListableBeanFactory beanFactory
                = new AnnotationConfigApplicationContext(Config.class)
                .getBeanFactory();

        StandardEvaluationContext context = new StandardEvaluationContext();
        // 指定 BeanResolver
        context.setBeanResolver(new BeanFactoryResolver(beanFactory));
        // 指定 Variable
        context.setVariable("v", "test");

        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression("@a");
        A a = expression.getValue(context, A.class);
        System.out.println(a.getName());

        Expression expression1 = parser.parseExpression("#v");
        System.out.println(expression1.getValue(context));
    }

}

这是一段 SpEL 解析的代码:

  • 指定了 BeanFactoryResolver 因此支持 @beanName 的解析
  • 添加了参数 Variable 支持自定义参数

CacheOperationExpressionEvaluator

class CacheOperationExpressionEvaluator extends CachedExpressionEvaluator {

	// ...

	// key SpEL 表达式缓存
	private final Map<ExpressionKey, Expression> keyCache = new ConcurrentHashMap<>(64);

	// condition SpEL 表达式缓存
	private final Map<ExpressionKey, Expression> conditionCache = new ConcurrentHashMap<>(64);

	// unless SpEL 表达式缓存
	private final Map<ExpressionKey, Expression> unlessCache = new ConcurrentHashMap<>(64);

	/**
	 * 创建对应的 EvaluationContext 
	 */
	public EvaluationContext createEvaluationContext(Collection<? extends Cache> caches,
			Method method, Object[] args, Object target, Class<?> targetClass, Method targetMethod,
			@Nullable Object result, @Nullable BeanFactory beanFactory) {

		// 这里就是为什么支持解析 #caches #target #targetClass #method #methodName #a1(#p1)
		CacheExpressionRootObject rootObject = new CacheExpressionRootObject(
				caches, method, args, target, targetClass);
		CacheEvaluationContext evaluationContext = new CacheEvaluationContext(
				rootObject, targetMethod, args, getParameterNameDiscoverer());
		if (result == RESULT_UNAVAILABLE) {
			evaluationContext.addUnavailableVariable(RESULT_VARIABLE);
		}
		else if (result != NO_RESULT) {
			// 这里就是为什么支持解析 #result
			evaluationContext.setVariable(RESULT_VARIABLE, result);
		}
		if (beanFactory != null) {
			// 这里表示支持 @beanName(&factoryBeanName) 的解析
			evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
		}
		return evaluationContext;
	}

	// 基于 SpEL 表达式计算 key
	@Nullable
	public Object key(String keyExpression, AnnotatedElementKey methodKey, EvaluationContext evalContext) {
		return getExpression(this.keyCache, methodKey, keyExpression).getValue(evalContext);
	}

	// condition SpEL 表达式计算结果是否为 True
	public boolean condition(String conditionExpression, AnnotatedElementKey methodKey, EvaluationContext evalContext) {
		return (Boolean.TRUE.equals(getExpression(this.conditionCache, methodKey, conditionExpression).getValue(
				evalContext, Boolean.class)));
	}

	// unless SpEL 表达式计算结果是否为 True
	public boolean unless(String unlessExpression, AnnotatedElementKey methodKey, EvaluationContext evalContext) {
		return (Boolean.TRUE.equals(getExpression(this.unlessCache, methodKey, unlessExpression).getValue(
				evalContext, Boolean.class)));
	}

	// ...

}
  • CacheOperation 相关注解的部分属性比如 key condition unless 都是支持 SpEL 表达式解析的,该类是对 EvaluationContext 的构造和对应表达式计算的一个封装
  • 父类 CachedExpressionEvaluator 提供了对 Expression 的缓存
  • createEvaluationContext 方法用于创建一个对应的 EvaluationContext 上下文用于计算表达式的值,其中 CacheExpressionRootObject 根对象提供了对 #method #target 等表达式的支持,在需要的情况下也制定了 result 变量以支持 #result 表达式的计算
  • 依此提供了对 key condition unless 表达式计算的实现

CacheOperationInvocationContext

/**
 * 缓存操作执行的上下文:包括 target method CacheOperation args
 */
public interface CacheOperationInvocationContext<O extends BasicOperation> {

	O getOperation();

	Object getTarget();

	Method getMethod();

	Object[] getArgs();

}

顶层接口,抽象了缓存操作的执行上下文

CacheOperationContext

	protected class CacheOperationContext implements CacheOperationInvocationContext<CacheOperation> {

		// ...

		// 是否满足 condition 条件
		protected boolean isConditionPassing(@Nullable Object result) {
			if (this.conditionPassing == null) {
				if (StringUtils.hasText(this.metadata.operation.getCondition())) {
					EvaluationContext evaluationContext = createEvaluationContext(result);

					// 基于 CacheOperationExpressionEvaluator::condition 方法
					this.conditionPassing = evaluator.condition(this.metadata.operation.getCondition(),
							this.metadata.methodKey, evaluationContext);
				}
				else {
					this.conditionPassing = true;
				}
			}
			return this.conditionPassing;
		}

		// 是否缓存目标结果,即 unless 条件判断
		protected boolean canPutToCache(@Nullable Object value) {
			String unless = "";

			// 只有 Cacheable 和 CachePut 支持 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);
				// 基于 CacheOperationExpressionEvaluator::unless 方法
				// unless 除...之外
				return !evaluator.unless(unless, this.metadata.methodKey, evaluationContext);
			}

			// 未指定就是执行缓存操作
			return true;
		}

		// 生成对应的缓存 key
		@Nullable
		protected Object generateKey(@Nullable Object result) {
			// 如果指定了 key 就基于 key 表达式计算
			if (StringUtils.hasText(this.metadata.operation.getKey())) {
				EvaluationContext evaluationContext = createEvaluationContext(result);
				return evaluator.key(this.metadata.operation.getKey(), this.metadata.methodKey, evaluationContext);
			}
			// 否则就由 keyGenerator 生成
			return this.metadata.keyGenerator.generate(this.target, this.metadata.method, this.args);
		}

		// 基于 CacheOperationExpressionEvaluator::createEvaluationContext 获取对应的 EvaluationContext 
		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);
		}

		// ...
		
	}
  • Spring Cache 提供的内置实现,封装 CacheOperation 执行的上下文信息
  • 提供 isConditionPassing canPutToCache generateKey 等方法来支持具体的缓存行为,比如 缓存的 key 基于 condition 判断是否触发缓存 基于 unless 判断是否缓存目标结果
  • 其中上述表达式的计算依赖于 CacheOperationExpressionEvaluator

总结

  • CacheOperationInvocationContext 是对缓存操作执行上下文的封装,它主要提供了对缓存操作对应属性值的解析
  • 其中针对 SpEL 表达式的支持基于 CacheOperationExpressionEvaluator 实现

上一篇:【Spring Cache】二 Spring 缓存操作相关注解及属性

下一篇:【Spring Cache】四 CacheOperation CacheOperationSource CacheAnnotationParser

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值