SpEl及@Value的SpEl表达式源码分析
Posted jazon@
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpEl及@Value的SpEl表达式源码分析相关的知识,希望对你有一定的参考价值。
文章目录
SpEl使用例子
public class SpElDemo
public static void main(String[] args)
Stu stu = new Stu();
stu.setName("xxl");
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();
standardEvaluationContext.setRootObject(new StuHandler());
standardEvaluationContext.setVariable("stu", stu);
String ret = spelExpressionParser.parseExpression("println(#stu)").getValue(standardEvaluationContext, String.class);
String retStr = spelExpressionParser.parseExpression("#stu.myAge()").getValue(standardEvaluationContext, String.class);
String retStr2 = spelExpressionParser.parseExpression("test.myAge()").getValue(standardEvaluationContext, String.class);
System.out.println(ret);
System.out.println(retStr);
System.out.println(retStr2);
public class Stu
private String name;
public String myAge()
System.out.println("myage");
return "myage";
public class StuHandler
private Stu test = new Stu();
public String println(Stu stu)
System.out.println(stu);
return "finished";
输出结果
Stu(name=xxl)
myage
myage
finished
myage
myage
EvaluationContext: 表达式执行的上下文环境,一般实现有StandardEvaluationContext
,表达式解析时将会使用context的根对象(RootObject),变量(Variable)等。MethodBasedEvaluationContext
继承了StandardEvaluationContext,会将method的变量载入到variable之中
默认情况下, 由于println方法前没有指定对象,println
方法指向的是RootObject,如果要调用其他对象的,需要将对象设置到Variable中,并指定对象#stu.myAge()
。如果属性前不加#
,如test.myAge()
则是访问到rootObject的属性。
@Value使用SpEl解析源码分析
关键方法:org.springframework.context.expression.StandardBeanExpressionResolver#evaluate
public Object evaluate(@Nullable String value, BeanExpressionContext evalContext) throws BeansException
if (!StringUtils.hasLength(value))
return value;
try
// 获取Expression
Expression expr = this.expressionCache.get(value);
if (expr == null)
expr = this.expressionParser.parseExpression(value, this.beanExpressionParserContext);
this.expressionCache.put(value, expr);
StandardEvaluationContext sec = this.evaluationCache.get(evalContext);
if (sec == null)
// 设置RootObject为BeanExpressionContext
sec = new StandardEvaluationContext(evalContext);
// 属性访问器,用于访问RootObject的属性,可以设置多个,这里生效的就第一个
// 适用于RootObject为BeanExpressionContext的属性访问器
sec.addPropertyAccessor(new BeanExpressionContextAccessor());
// 适用于RootObject为BeanFactory的属性访问器
sec.addPropertyAccessor(new BeanFactoryAccessor());
// 适用于RootObject为Map的属性访问器
sec.addPropertyAccessor(new MapAccessor());
// 适用于RootObject为Environment的属性访问器
sec.addPropertyAccessor(new EnvironmentAccessor());
// bean查找器,在SpEl中要找一个bean可以使用@beanName或者&beanName,底层就是使用的BeanResolver去找的
sec.setBeanResolver(new BeanFactoryResolver(evalContext.getBeanFactory()));
// TypeLocator底层确定使用的classLoader,
sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader()));
ConversionService conversionService = evalContext.getBeanFactory().getConversionService();
if (conversionService != null)
// spel解析过程使用的类型转换
sec.setTypeConverter(new StandardTypeConverter(conversionService));
customizeEvaluationContext(sec);
this.evaluationCache.put(evalContext, sec);
// 获取结果
return expr.getValue(sec);
catch (Throwable ex)
throw new BeanExpressionException("Expression parsing failed", ex);
以上是关于SpEl及@Value的SpEl表达式源码分析的主要内容,如果未能解决你的问题,请参考以下文章