Spring Expression Language

阅读数:117 评论数:0

跳转到新版页面

分类

python/Java

正文

一、SPEL

SpEL(Spring Expression Language),即Spring表达式语言, 语法类似于 EL 表达式 ,但提供了显式方法调用和基本字符串模板函数等特性 ,能够在运行时构建复杂的表达式。

 SpEL 虽然作为 Spring 家族中表达式求值的基础,但却可以被独立使用。

在单独使用 SpEL 时,需要创建一个 ExpressionParser 解析器,并提供一个 EvaluationContext 求值上下文 。 但在 Spring 框架中,仅需要配置一个 SpEL 表达式( Spring bean 定义)即可。SpEL 解析器、求值上下文、根对象和其他预定义变量等基础设施都会被隐含创建

二、EvaluationContext

EvaluationContext 接口定义了获取属性、方法、域字段解析器及类型转换器。

1、StandardEvaluationContext

StandardEvaluationContext 使用的是反射机制来操作对象 。 为了提高性能,他会在其内部缓存 java.lang.reflect 的 Method、Field 和 Constructor 实例。

StandardEvaluationContext 类可以通过构造函数来传递求值根对象,也可以通过方法 setRootObject() 来指定求值根对象。 可以使用 setVariable() 来设置变量;使用 registerFunction(String name, Method method)来注册自定义函数。

在StandardEvaluationContext中,我们还可以注册自定的构造函数转换器ContructorResolvers、方法转换器MethodResolvers及属性转换器PropertyAccessors来定制表达式的解析方式。

默认情况下,SpEL使用的是ConversionService来执行转换服务,它会根据源类型与目录类型来选择合适的转换器。Spring内置了很多转换器。

public class GenericConvertExample {
    public List<Integer> nums = new ArrayList();

    public static void main(String[] args) {

        GenericConvertExample example = new GenericConvertExample();
        example.nums.add(1);

        //创建表达式上下文
        StandardEvaluationContext context = new StandardEvaluationContext(example);
        //创建表达式解析器
        ExpressionParser parser = new SpelExpressionParser();

        String expression = "nums[0]";
        //自动将 2 转换为 Integer 类型
        parser.parseExpression(expression).setValue(context, 2);
        System.out.println("nums:" + example.nums);

        //抛出 ConverterNotFoundException
        try {
            parser.parseExpression(expression).setValue(context, true);
        } catch (EvaluationException e) {
            e.printStackTrace();s
        } catch (ParseException e) {
            e.printStackTrace();
        }

    }
}

(1)在上下文中设置变量,然后在表达式中引用这些变量

context.setVariable("greeting", "Hello, World!");

(2)注册函数

如果你有一些自定义逻辑,你可以将方法注册为函数,然后在表达式中调用:

public class StringUtils {
    public static String concatenate(String one, String two) {
        return one + two;
    }
}

// 注册函数
context.registerFunction("concat", StringUtils.class.getDeclaredMethod("concatenate", String.class, String.class));

// 然后在表达式中使用
String result = parser.parseExpression("#concat('Hello', ' World')").getValue(context, String.class);

(3)设置根对象

你可以设置一个根对象,表达式将默认使用这个根对象的属性和方法:

class Simple {
    public String message = "Hello, World!";
}

Simple simple = new Simple();
context.setRootObject(simple);

(4)使用类型转换器

StandardEvaluationContext 可以配置自定义的类型转换器来处理表达式结果的类型转换:

ConversionService conversionService = new DefaultConversionService();
context.setTypeConverter(new StandardTypeConverter(conversionService));

(5)评估表达式

ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("('Hello' + ' World').toUpperCase()");

String result = expression.getValue(context, String.class);
System.out.println(result); // 输出: HELLO WORLD

(6)使用属性访问器

如果你需要自定义属性的解析,你可以添加自定义的属性访问器:

context.addPropertyAccessor(new CustomPropertyAccessor());

(7)安全性

从 Spring 4.1 开始,StandardEvaluationContext 有一个用于配置安全性的方法,可以限制哪些类型可以被访问和操作:

context.setBeanResolver(new MySecureBeanResolver());

三、SpelCompiler

默认情况下, SpEL 表达式只有在求值时才会进行表达式计算,所以表达式可以在运行时进行动态修改。但如果一个表达式被重复调用的次数很多,那么就必须使用SpelCompiler 编译器来保证性能。

SpelCompiler 编译器会将表达式编译成字节码,只有在运行时表达式发生变化时,才会被重新编译。

//Spel 解析配置器
SpelParserConfiguration configuration=new SpelParserConfiguration
        (SpelCompilerMode.IMMEDIATE,CompilerExample.class.getClassLoader());

//解析器
SpelExpressionParser parser=new SpelExpressionParser(configuration);

//上下文
EvaluationContext context=new StandardEvaluationContext(new Account("Deniro"));

//表达式
String expression="getName()";

//解析表达式
SpelExpression spelExpression=parser.parseRaw(expression);

System.out.println(spelExpression.getValue(context));

Spel解析配置器有三种编译模式

OFF 不启用编译模式(默认)
MIXED 在混合模式下,随着时间的推移,表达式会从解释模式自动切换到编译模式。即前面使用解释模式,当调用次数达到某个阈值后,改为使用编译模式。
IMMEDIATE 启用编译模式。实际内部在调用第一次之后,才会真正使用编译模式。

四、使用

1、依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>${spring.version}</version>
</dependency>

2、简单示例

ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("6+2");
Integer result = (Integer) expression.getValue();
System.out.println("result:" + result);

3、获取某个类实例的属性值

可以在表达式中引用根对象的属性,在解析表达式时,会在内部使用反射会从根对象中获取属性的值。

public class Account {

    private String name;

    public Account(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

我们通过表达式来获取 Account 实例中的 name 值:

Account account=new Account("Deniro");
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context=new StandardEvaluationContext(account);
Expression expression = parser.parseExpression("name");
String result = expression.getValue(context,String.class);
System.out.println("result:" + result);



相关推荐

(1)Spring MVC是一个基于DispatcherServlet的MVC框架,DispatcherServlet是继承自HttpServlet的。Spring的IOC和AOP主要就用了java的

如果一个类交张spring管理,比如 &lt;bean id="foo1" class="demo.scope.foo" /&gt; 不指明scope就是单例。</p

@PathParam的声明允许你在URI路径中去映射你的方法将使用的参数。 @Path("/library") pu

方式1:通过@PostConstruct和@PreDestroy方法。 从Java EE5开始,Servlet增加了两个影响Servlet生命周期的注解。 方式2:通

一、概述 1、spring容器 spring中有三种bean容器:BeanFactory、ApplicationContext、WebApplicationContext。 (1)BeanFactor

有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,然后这样如果执行大量测试的话就很麻烦,并且不直观,如果想对执行的时间做进

一、request uri部分 @PathVariable 获取路径参数,形如url/{id} 二、request header部分 @RequestHeade

一、概述 springboot中有两种方式使用kafka时,直接使用kafka-client连接kafka服务;另一种是使用spring-kafka框架来连接kafka。 1、版本兼容 使用时要注意版

当然可以自己写redis的工具类,或者使用第三方开源jar包或代码,这里使用spring boot的集成类。 一、pom依赖 <dependency> <gro

websocket协议基于tcp的网络协议,它实现浏览器与器全双工通信。 spring boot2 +websocket 1、添加依赖 <pre clas