import java.lang.reflect.Method;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
public class StudySpEL {
public static void main(String[] args) {
getStart();
parseContext();
regFunction();
}
public static void getStart()
{
//待解析的字符串,注意整个字符串是要解析的,如果要解析的字符串中包含
//字符串要使用单引号,例如要写成下面toParseString的样子而不是
//"welcome to el world + #name"这样,因为不加引号,解析器
//就会把它当做字段或者属性来解析,而没有这个属性或者字段就会出错
final String toParseString = "'welcome to el world' + #name";
//解析器,spring为我们提供了一个SpelExpressionParser解析器
ExpressionParser parser = new SpelExpressionParser();
//用解析器把待解析的字符串解析为表达式Expression
//Expression的结构就是一些AST节点,例如:"'welcome to el world' + #name"字符串
//就被拆分为welcome to el wolrd #name这样的节点,方便被EvaluationContext计算
Expression expression = parser.parseExpression(toParseString);
//EvaluationContext就是计算的上下文,用来替换Expression中的变量表达式的
//例如下面就是把待解析字符串(上下文)中的name变量替换为everybody
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("name", "everybody");
Object result = expression.getValue(context);
System.out.println(result);
}
/**
* 想spring中就会发现有 @Value("#{T(Math).PI * 4^2}") 这样的注解
* 它的待解析的字符串是#{}这样的形式,怎么办,spring还有一个解析的上下文接口
* ParserContext 它提供了一个默认的实现ParserContext.TEMPLATE_EXPRESSION
* 就是解析以#{开头以}结束的字符串,当然也可以自己实现ParserContext接口
*/
public static void parseContext()
{
//SpEL 支持+ - * / ^ % 等运算
//SpEL 支持类型表达式 要求除了java.lang包以外的类使用类的全限定名称
//T(Math).PI 就是访问java.lang.Math 的静态字段PI
final String toParseString = "#{T(Math).PI * 4^2}";
ExpressionParser parser = new SpelExpressionParser();
//因为待解析字符串是#{}这样的形式所以使用ParserContext上下文,ParserContext.TEMPLATE_EXPRESSION
Expression expression = parser.parseExpression(toParseString, ParserContext.TEMPLATE_EXPRESSION);
Object value = expression.getValue(); //PI*16
System.out.println(value);
}
/**
* SpEL支持自定义函数,只能是静态方法
*/
public static void regFunction()
{
final String toParseString = "#customerFunction(4,6)";
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(toParseString);
StandardEvaluationContext context = new StandardEvaluationContext();
Method customerFuction = null;
try {
customerFuction = StudySpEL.class.getDeclaredMethod("customerFunction", int.class,int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
//StandardEvaluationContext 才有registerFunction方法,也可以使用setVariable
//注册方法
context.registerFunction("customerFunction", customerFuction);
Integer value = expression.getValue(context, int.class);
System.out.println(value);
}
public static int customerFunction(int a,int b)
{
return a+b;
}
}
虽然我们平时可能很少用到很复杂的表达式,想解析mybatis的Mapper文件这种级别的,但是我们可以在注解上使用表达式,可以让注解有更多的动态特性,在结合aop,可以把一些实现做的很优雅。所以了解一点spring的EL总是没有坏处的。