Files
rikako-note/spring/spring boot/spel.md
2023-06-29 17:25:28 +08:00

5.7 KiB
Raw Blame History

Spel

Spel表达式计算

示例

如下是一个Spel表达式计算示例

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'"); 
String message = (String) exp.getValue();
// 最终message计算的值是'Hello World'

Concept

ExpressionParser接口用于对表达式字符串进行解析,在上述示例中,表达式字符串是一个由单引号包围起来的字符串字面量。

Expression接口则是负责对表达式字符串进行计算。

在调用parser.parseExpressionexp.getValue,分别会抛出ParseExceptionEvaluationException异常。

Spel支持许多特性例如调用方法访问属性调用构造方法等示例如下

调用方法

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')"); 
String message = (String) exp.getValue();
// message值为Hello World!

调用属性

ExpressionParser parser = new SpelExpressionParser();

// invokes 'getBytes().length'
Expression exp = parser.parseExpression("'Hello World'.bytes.length"); 
int length = (Integer) exp.getValue();

调用构造器

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); 
String message = exp.getValue(String.class);

通过public <T> T getValue(Class<T> desiredResultType)方法向getValue方法传递一个Class对象可以避免在调用getValue方法调用之后需要将返回值手动转化为特定类型。如果类型转化失败会抛出一个EvaluationException异常。

在特定对象上计算表达式

Spel支持在一个特定的对象上该对象通常被称作root object进行计算例如如下示例

// Create and set a calendar
GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9);

// The constructor arguments are name, birthday, and nationality.
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");

ExpressionParser parser = new SpelExpressionParser();

Expression exp = parser.parseExpression("name"); // Parse name as an expression
String name = (String) exp.getValue(tesla);
// name == "Nikola Tesla"

exp = parser.parseExpression("name == 'Nikola Tesla'");
boolean result = exp.getValue(tesla, Boolean.class);
// result == true

EvaluationContext

EvalutaionContext用于给表达式提供一个执行的上下文环境通过EvalutaionContext可以向context中放置一个变量并且在后续中使用该变量

// 向context中放入一个list变量
ctx.setVariable("list",list)

// 在后续表达式中即可使用放入的list变量
// 获取放入context中的list变量的值
parser.parseExpression("#list[0]").getValue(ctx);
// 设置context中list变量的值
parser.parseExpression("#list[0]").setValue(ctx , "false");

EvaluationContext实现类

  • SimpleEvaluationContext实现了Spel语言的部分特性
  • StandardEvaluationContext实现了Spel语言的全部特性

TypeConversion

默认情况下spel会使用org.springframework.core.convert.ConversionService中的Conversion Service。该conversion service包含内置的类型转换并且可以为类型之间指定自定义的类型转换。该转换是支持泛型的。

如下为支持泛型的示例:

class Simple {
	public List<Boolean> booleanList = new ArrayList<>();
}

Simple simple = new Simple();
simple.booleanList.add(true);

EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

// "false" is passed in here as a String. SpEL and the conversion service
// will recognize that it needs to be a Boolean and convert it accordingly.
parser.parseExpression("booleanList[0]").setValue(context, simple, "false");

// b is false
Boolean b = simple.booleanList.get(0);

在定义Bean对象时使用Spel表达式

可以通过@Value注解来为bean对象的域、方法参数、构造器参数指定默认值。通过如下方式来指定表达式:

  • #{ <expression string> }.

为field指定默认值

public class FieldValueTestBean {

	@Value("#{ systemProperties['user.region'] }")
	private String defaultLocale;

	public void setDefaultLocale(String defaultLocale) {
		this.defaultLocale = defaultLocale;
	}

	public String getDefaultLocale() {
		return this.defaultLocale;
	}
}

通过setter为field指定默认值

public class PropertyValueTestBean {

	private String defaultLocale;

	@Value("#{ systemProperties['user.region'] }")
	public void setDefaultLocale(String defaultLocale) {
		this.defaultLocale = defaultLocale;
	}

	public String getDefaultLocale() {
		return this.defaultLocale;
	}
}

@Autowired方法和构造器

@Autowired方法和构造器可以使用@Value注解为参数指定默认值

public class SimpleMovieLister {

	private MovieFinder movieFinder;
	private String defaultLocale;

	@Autowired
	public void configure(MovieFinder movieFinder,
			@Value("#{ systemProperties['user.region'] }") String defaultLocale) {
		this.movieFinder = movieFinder;
		this.defaultLocale = defaultLocale;
	}

	// ...
}
public class MovieRecommender {

	private String defaultLocale;

	private CustomerPreferenceDao customerPreferenceDao;

	public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,
			@Value("#{systemProperties['user.country']}") String defaultLocale) {
		this.customerPreferenceDao = customerPreferenceDao;
		this.defaultLocale = defaultLocale;
	}

	// ...
}