前言
Spring表达式语言(简称“SpEL”)是一种功能强大的表达式语言,支持在运行时查询和操作对象图。该语言语法类似于Unified EL,但提供了额外的功能,最显著的是方法调用和基本的字符串模板功能。
虽然还有其他几种Java表达式语言可用 — OGNL、MVEL和JBoss EL,仅举几个例子 — 创建Spring表达式语言是为了向Spring社区提供一种受良好支持的表达式语言,该语言可以在Spring产品组合中的所有产品中使用。它的语言特性是由Spring产品组合中项目的需求驱动的,包括Spring Tools for Eclipse中代码完成支持的工具需求。也就是说,SpEL基于一种技术——gnostic API,如果需要,它可以集成其他表达式语言实现。
虽然SpEL是Spring产品组合中表达式求值的基础,但它并不直接与Spring绑定,可以独立使用。为了自圆其说,本章中的许多例子都使用了SpEL,就好像它是一种独立的表达语言一样。这需要创建一些自举基础结构类,例如解析器。大多数Spring用户不需要处理这个基础设施,而是可以只编写用于评估的表达式字符串。这种典型使用的一个示例是将SpEL集成到创建基于XML或注释的bean定义中,如定义bean定义的Expression支持中所示。
4.1 Evaluation
package org.example.validator.evaluation;
import org.example.validator.po.Inventor;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import java.util.GregorianCalendar;
/**
* Create by zjg on 2024/4/21
*/
public class Main {
public static void main(String[] args) {
System.out.println(parse("'Hello Spel'",String.class));//字符串
System.out.println(parse("'Hello World'.concat('!')",String.class));//字符串连接
System.out.println(new String(parse("'Hello World'.bytes",byte[].class)));//得到字节数组
System.out.println(parse("'Hello World'.bytes.length",Integer.class));//得到参数长度
System.out.println(parse("new String('hello world').toUpperCase()",String.class));//大写转换
System.out.println(parse("new String('HELLO WORLD').toLowerCase()",String.class));//小写转换
// 日期
GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9);
// 创建对象及初始化
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
String name = getValue("name",String.class,tesla);//获取tesla的name属性值
System.out.println(name);
boolean result = getValue("name == 'Nikola Tesla'",Boolean.class,tesla);//获取tesla的name属性值和字符串对比
System.out.println(result);
}
public static <T> T parse(String expressionString, Class<T> clazz){
ExpressionParser parser = new SpelExpressionParser();
return clazz.cast(parser.parseExpression(expressionString).getValue());
}
public static <T> T getValue(String expressionString, Class<T> clazz,Object object){
ExpressionParser parser = new SpelExpressionParser();
return clazz.cast(parser.parseExpression(expressionString).getValue(object));
}
}
4.1.1. Understanding EvaluationContext
package org.example.validator.evaluation;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import java.util.ArrayList;
import java.util.List;
/**
* Create by zjg on 2024/4/21
*/
public class UnderstandingEvaluationContext {
public static void main(String[] args) {
Simple simple = new Simple();
simple.booleanList.add(true);
simple.booleanList.add(true);
simple.booleanList.add(false);
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
ExpressionParser parser = new SpelExpressionParser();//spring内置转换服务
parser.parseExpression("booleanList[0]").setValue(context, simple, "false");//设置列表下表0的值为false
simple.booleanList.forEach(System.out::println);
}
}
class Simple {
public List<Boolean> booleanList = new ArrayList<Boolean>();
}
4.1.2. Parser Configuration
package org.example.validator.evaluation;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import java.util.List;
/**
* Create by zjg on 2024/4/21
*/
public class ParserConfiguration {
public static void main(String[] args) {
class Demo {
public List<String> list;
}
//自动null引用,集合自动增长
SpelParserConfiguration config = new SpelParserConfiguration(true, true);
ExpressionParser parser = new SpelExpressionParser(config);
Expression expression = parser.parseExpression("list[3]");
Demo demo = new Demo();
Object o = expression.getValue(demo);
for(int i=0;i<demo.list.size();i++){//有4个空值
System.out.println(i+""+demo.list.get(i));
}
}
}
4.1.3. SpEL Compilation
package org.example.validator.evaluation;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.SpelCompilerMode;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
/**
* Create by zjg on 2024/4/21
*/
public class SpelCompliation {
public static void main(String[] args) {
class MyMessage {
public String payload;
public void setPayload(String payload) {
this.payload = payload;
}
}
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
SpelCompliation.class.getClassLoader());//指定编译器模式(立即获取)
SpelExpressionParser parser = new SpelExpressionParser(config);
Expression expr = parser.parseExpression("payload");
MyMessage message = new MyMessage();
message.setPayload("ssr");
Object payload = expr.getValue(message);
System.out.println(payload);
}
}
4.2. Expressions in Bean Definitions
4.2.1. XML Configuration
4.2.1.1 实体类
package org.example.validator.expressions.xml.po;
/**
* Create by zjg on 2024/4/22
*/
public class NumberGuess {
private double randomNumber;
public double getRandomNumber() {
return randomNumber;
}
public void setRandomNumber(double randomNumber) {
this.randomNumber = randomNumber;
}
@Override
public String toString() {
return "NumberGuess{" +
"randomNumber=" + randomNumber +
'}';
}
}
package org.example.validator.expressions.xml.po;
/**
* Create by zjg on 2024/4/22
*/
public class ShapeGuess {
private double initialShapeSeed;
public double getInitialShapeSeed() {
return initialShapeSeed;
}
public void setInitialShapeSeed(double initialShapeSeed) {
this.initialShapeSeed = initialShapeSeed;
}
@Override
public String toString() {
return "ShapeGuess{" +
"initialShapeSeed=" + initialShapeSeed +
'}';
}
}
package org.example.validator.expressions.xml.po;
/**
* Create by zjg on 2024/4/22
*/
public class TaxCalculator {
private String defaultLocale;
public String getDefaultLocale() {
return defaultLocale;
}
public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}
@Override
public String toString() {
return "TaxCalculator{" +
"defaultLocale='" + defaultLocale + '\'' +
'}';
}
}
4.2.1.2 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="numberGuess" class="org.example.validator.expressions.xml.po.NumberGuess">
<property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>
</bean>
<bean id="taxCalculator" class="org.example.validator.expressions.xml.po.TaxCalculator">
<property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>
</bean>
<bean id="shapeGuess" class="org.example.validator.expressions.xml.po.ShapeGuess">
<property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>
</bean>
</beans>
4.2.1.3 测试类
package org.example.validator.expressions.xml;
import org.example.validator.expressions.xml.po.NumberGuess;
import org.example.validator.expressions.xml.po.ShapeGuess;
import org.example.validator.expressions.xml.po.TaxCalculator;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
/**
* Create by zjg on 2024/4/22
*/
@SpringJUnitConfig(locations = "classpath:spring-spel.xml")
public class SpringTest {
@Autowired
NumberGuess numberGuess;
@Autowired
TaxCalculator taxCalculator;
@Autowired
ShapeGuess shapeGuess;
@Test
public void test(){
System.out.println(numberGuess);
System.out.println(taxCalculator);
System.out.println(shapeGuess);
}
}
NumberGuess{randomNumber=36.044191193759225}
TaxCalculator{defaultLocale=‘null’}
ShapeGuess{initialShapeSeed=36.044191193759225}
4.2.2. Annotation Configuration
4.2.2.1 实体类
package org.example.validator.expressions.annotation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* Create by zjg on 2024/4/22
*/
@Component
public class FieldValueTestBean {
@Value("#{ systemProperties['user.region']?: 'CN' }")
private String defaultLocale;
public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}
public String getDefaultLocale() {
return this.defaultLocale;
}
@Override
public String toString() {
return "FieldValueTestBean{" +
"defaultLocale='" + defaultLocale + '\'' +
'}';
}
}
package org.example.validator.expressions.annotation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* Create by zjg on 2024/4/22
*/
@Component
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;
}
@Override
public String toString() {
return "MovieRecommender{" +
"defaultLocale='" + defaultLocale + '\'' +
", customerPreferenceDao=" + customerPreferenceDao +
'}';
}
}
package org.example.validator.expressions.annotation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* Create by zjg on 2024/4/22
*/
@Component
public class PropertyValueTestBean {
private String defaultLocale;
@Value("#{ systemProperties['user.region'] }")
public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}
public String getDefaultLocale() {
return this.defaultLocale;
}
@Override
public String toString() {
return "PropertyValueTestBean{" +
"defaultLocale='" + defaultLocale + '\'' +
'}';
}
}
package org.example.validator.expressions.annotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* Create by zjg on 2024/4/22
*/
@Component
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;
}
@Override
public String toString() {
return "SimpleMovieLister{" +
"movieFinder=" + movieFinder +
", defaultLocale='" + defaultLocale + '\'' +
'}';
}
}
4.2.2.2 配置类
package org.example.validator.expressions.annotation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* Create by zjg on 2024/4/22
*/
@ComponentScan("org.example.validator.expressions.annotation")
@Configuration
public class SpringConfig {
@Bean
public MovieFinder movieFinder(){
return new MovieFinder();
}
@Bean
public CustomerPreferenceDao customerPreferenceDao(){
return new CustomerPreferenceDao();
}
}
class MovieFinder{}
class CustomerPreferenceDao{}
4.2.2.3 测试类
package org.example.validator.expressions.annotation;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
/**
* Create by zjg on 2024/4/22
*/
@SpringJUnitConfig(SpringConfig.class)
public class SpringApplication {
@Autowired
FieldValueTestBean fieldValueTestBean;
@Autowired
PropertyValueTestBean propertyValueTestBean;
@Autowired
SimpleMovieLister simpleMovieLister;
@Autowired
MovieRecommender movieRecommender;
@Test
public void test() {
System.out.println(fieldValueTestBean);
System.out.println(propertyValueTestBean);
System.out.println(simpleMovieLister);
System.out.println(movieRecommender);
}
}
FieldValueTestBean{defaultLocale=‘null’}
PropertyValueTestBean{defaultLocale=‘null’}
SimpleMovieLister{movieFinder=org.example.validator.expressions.annotation.MovieFinder@1b1637e1, defaultLocale=‘null’}
MovieRecommender{defaultLocale=‘CN’, customerPreferenceDao=org.example.validator.expressions.annotation.CustomerPreferenceDao@18151a14}
4.2.2.4 常用系统变量和所有系统变量
package org.example.validator.expressions.annotation;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
/**
* Create by zjg on 2024/4/22
*/
@SpringJUnitConfig(SpringConfig.class)
public class SpringApplication {
@Value("#{ systemProperties['user.name'] }")
private String name;
@Value("#{ systemProperties['user.dir'] }")
private String dir;
@Value("#{ systemProperties['user.country'] }")
private String country;
@Value("#{ systemProperties['user.language'] }")
private String language;
@Value("#{ systemProperties['PID'] }")
private String pid;
@Test
public void systemProperties() {
System.out.println(name);
System.out.println(dir);
System.out.println(country);
System.out.println(language);
System.out.println(pid);
System.getProperties().forEach((k,v)->{
System.out.println(k+":"+v);
});
}
}
总结
尽管我已经参考官方案例去编写完整的案例,但是案例数过多导致文章篇幅过长,但是每个案例都有它的用处,为了保证大家阅读起来的体验感,从这里进行拆分,4.3. Language Reference会在下一个章节里介绍,这一章节只介绍基础用法。
不重复造轮子,我们只是代码的搬运工。
建议大家先看我的文档,再看官方案例,然后你就会发现我写的有多差。
ps:开个玩笑,官方能跑的我能跑,官方不能跑的我也能跑,我写的很详细了,好吧。