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

181 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Spel
## Spel表达式计算
### 示例
如下是一个Spel表达式计算示例
```java
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();
// 最终message计算的值是'Hello World'
```
### Concept
`ExpressionParser`接口用于对表达式字符串进行解析,在上述示例中,表达式字符串是一个由单引号包围起来的字符串字面量。
`Expression`接口则是负责对表达式字符串进行计算。
在调用`parser.parseExpression``exp.getValue`,分别会抛出`ParseException``EvaluationException`异常。
Spel支持许多特性例如调用方法访问属性调用构造方法等示例如下
#### 调用方法
```java
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
String message = (String) exp.getValue();
// message值为Hello World!
```
#### 调用属性
```java
ExpressionParser parser = new SpelExpressionParser();
// invokes 'getBytes().length'
Expression exp = parser.parseExpression("'Hello World'.bytes.length");
int length = (Integer) exp.getValue();
```
#### 调用构造器
```java
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进行计算例如如下示例
```java
// 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中放置一个变量并且在后续中使用该变量
```java
// 向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包含内置的类型转换并且可以为类型之间指定自定义的类型转换。该转换是支持泛型的。
如下为支持泛型的示例:
```java
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指定默认值
```java
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指定默认值
```java
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注解为参数指定默认值
```java
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;
}
// ...
}
```
```java
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;
}
// ...
}
```