From 0bb208569fa3e33ad9d38739e088fd661077e250 Mon Sep 17 00:00:00 2001 From: Rikako Wu <496063163@qq.com> Date: Thu, 29 Jun 2023 17:25:28 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=85=E8=AF=BBspel=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring/spring boot/spel.md | 180 +++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 spring/spring boot/spel.md diff --git a/spring/spring boot/spel.md b/spring/spring boot/spel.md new file mode 100644 index 0000000..c1a5377 --- /dev/null +++ b/spring/spring boot/spel.md @@ -0,0 +1,180 @@ +# 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 getValue(Class 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 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对象的域、方法参数、构造器参数指定默认值。通过如下方式来指定表达式: +- `#{ }.` + +#### 为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; + } + + // ... +} +``` + + + +