首页 > 其他分享 >【深入浅出Spring原理及实战】「夯实基础系列」360全方位透析和探究SpringEL的开发实战指南(序章)

【深入浅出Spring原理及实战】「夯实基础系列」360全方位透析和探究SpringEL的开发实战指南(序章)

时间:2023-07-24 19:32:56浏览次数:44  
标签:实战 Spring parser 序章 SpEL exp 字符串 getValue 表达式

Spring表达式语言(SpEL)

本文将介绍 SpEL 的功能、API 和语言语法。

概念介绍

Spring 表达式语言(SpEL)是一种功能强大的表达式语言,用于在运行时查询和操作对象图。它的语法与 Unified EL 相似,但提供了更多功能,其中最主要的是方法调用和基本的字符串模板功能。

技术无关性

虽然还有其他几种 Java 表达式语言,如 OGNL、MVEL 和 JBoss EL 等,但创建 SpEL 的目的是为 Spring 社区提供一种支持良好的表达式语言,可用于 Spring 产品组合中的所有产品。SpEL 的语言特性是由 Spring 产品组合中的项目需求推动的,其中包括在基于 Eclipse 的 SpringSource 工具套件中支持代码补全的需求。尽管如此,SpEL 基于与技术无关的 API,允许在需要时集成其他表达式语言实现。


功能独立性

虽然 SpEL 是 Spring 产品组合中表达式评估的基础,但它与 Spring 没有直接联系,可以独立使用。为了实现自包含,本章中的许多示例将 SpEL 视为独立的表达式语言来使用。这种方式需要创建一些基础架构类,例如解析器。大多数 Spring 用户不需要直接处理这些基础结构,只需编写表达式字符串进行评估。

功能概览

表达式语言支持以下功能:

【深入浅出Spring原理及实战】「夯实基础系列」360全方位透析和探究SpringEL的开发实战指南(序章)_Express

Spring表达式接口进行表达式评估

以下代码介绍了如何使用 SpEL API 来评估字面字符串表达式 "Hello World":

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class SpELDemo {
    public static void main(String[] args) {
        // 创建表达式解析器
        ExpressionParser parser = new SpelExpressionParser();
        // 定义要评估的表达式
        Expression expression = parser.parseExpression("\"Hello World\"");
        // 通过表达式评估获取结果
        String result = expression.getValue(String.class);
        // 打印结果
        System.out.println(result);
    }
}

在上述代码中,我们首先创建了一个 SpEL 表达式解析器 SpelExpressionParser。然后,我们定义了要评估的表达式 "Hello World",并使用表达式解析器对其进行解析。接下来,通过调用 getValue() 方法来评估表达式并获取结果。最后,我们将结果打印出来。

代码案例分析

使用以下 SpEL 类和接口来处理消息变量,其位于 org.springframework.expression 及其子包和 spel.support 包中。

  • ExpressionParser 接口负责解析表达式字符串。在本例中,表达式字符串是一个字符串字面量,由周围的单引号表示。
  • Expression 接口负责评估先前定义的表达式字符串。在调用 parser.parseExpression()exp.getValue() 时可能会出现两种异常:ParseExceptionEvaluationException

SpEL 还支持其他功能,如调用方法、访问属性和调用构造函数。

举个例子,您可以在字符串字面量上调用 "concat" 方法来执行字符串拼接操作。

concat方法
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
String message = (String) exp.getValue();
bytes属性

当前的 message 值是 "Hello World!"。您可以通过以下方式调用 JavaBean 属性,例如字符串属性 "Bytes":

ExpressionParser parser = new SpelExpressionParser();
// invokes 'getBytes()'
Expression exp = parser.parseExpression("'Hello World'.bytes");  
byte[] bytes = (byte[]) exp.getValue();

以上代码将返回字符串属性 "Bytes" 的值。

属性访问操作

SpEL 还支持使用标准的 "点" 符号来访问嵌套属性,例如 prop1.prop2.prop3,以及设置属性值。此外,SpEL 还可以访问公共字段。 通过使用 SpEL,您可以轻松地访问嵌套属性的值:

prop1.prop2.prop3

以上代码将返回 prop1 属性中的 prop2 属性中的 prop3 属性的值。

同时,您也可以使用 SpEL 设置嵌套属性的值:

prop1.prop2.prop3 = newValue

以上代码将设置 prop1 属性中的 prop2 属性中的 prop3 属性的值为 newValue。

此外,SpEL 还可以访问公共字段:

fieldName

以上代码将返回公共字段 fieldName 的值。

代码案例
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) 泛型方法的使用。通过使用该方法,您无需手动将表达式的值转换为所需的结果类型。如果无法将值转换为 T 类型或使用已注册的类型转换器进行转换,则会抛出一个 EvaluationException 异常。

通常情况下,SpEL 的常见用法是提供一个表达式字符串,并对特定对象实例(称为根对象)进行求值。在这种情况下,您有两种选择,具体取决于每次调用表达式时,表达式所针对的对象是否会发生变化。

以下是一个示例,我们从 Inventor 类的实例中获取 name 属性:

// 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");
EvaluationContext context = new StandardEvaluationContext(tesla);
String name = (String) exp.getValue(context);

上述代码中,我们将 inventor 对象作为根对象传递给表达式的 getValue 方法,并指定要获取的属性名称为 "name"。返回的值将会被自动转换为指定的结果类型。

将字符串变量"name"的值设置为"Nikola Tesla"。 在StandardEvaluationContext类中,您可以指定要针对哪个对象评估"name"属性。 如果根对象很可能不会改变,您可以使用这种机制,只需在评估上下文中设置一次即可。 如果根对象可能会反复更改,则可以在每次调用getValue时提供,如下面的示例所示:

/ 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");
String name = (String) exp.getValue(tesla);

在这种情况下,发明家特斯拉直接提供给getValue方法。表达式评估基础架构会内部创建并管理一个默认的评估上下文,无需提供上下文实例。

使用标准评估上下文(StandardEvaluationContext)的构建成本相对较高,并且在重复使用过程中会积累缓存状态,从而使后续的表达式评估能够更快地执行。因此,最好在可能的情况下缓存并重复使用它们,而不是为每次表达式求值都构建新的上下文实例。

在某些情况下,我们希望在每次调用getValue时提供不同的根对象,但仍然使用配置好的评估上下文。在这种情况下,传递给调用的根对象将覆盖评估上下文中指定的任何根对象(如果有)。

案例介绍

作为最后一个介绍性示例,我们将使用之前的示例中的Inventor对象来演示如何使用布尔运算符。

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

总体分析

在独立使用SpEL时,通常需要创建解析器、解析表达式,并且可能还需要提供评估上下文和根上下文对象。不过,更常见的做法是将SpEL表达式字符串作为配置文件的一部分,例如Spring Bean或Spring Web Flow的定义。在这种情况下,解析器、评估上下文、根对象以及任何预定义变量都会被隐式设置,用户只需要指定表达式即可。

标签:实战,Spring,parser,序章,SpEL,exp,字符串,getValue,表达式
From: https://blog.51cto.com/alex4dream/6838263

相关文章

  • 实战演示:Apipost接口自动化测试
    Apipost提供了可视化的接口自动化测试平台,合理运用事物控制器、条件控制器、循环控制器等控制器,可以满足各种复杂测试需求。适用场景:复杂的多接口多场景回归测试比较费时费力,自动化测试平台搭建成本、维护成本太高。这里小编用电商平台购物流程来给大家介绍在Apipost中接口变量的......
  • springboot四
    SpringBoot集成Swagger在线接口文档1.Swagger简介1.1解决的问题随着互联网技术的发展,现在的网站架构基本都由原来的后端渲染,变成了前后端分离的形态,而且前端技术和后端技术在各自的道路上越走越远。前端和后端的唯一联系变成了API接口,所以API文档变成了前后端开发人......
  • QT从入门到实战完整版 P38
    手动调用绘图事件widget.h#ifndefWIDGET_H#defineWIDGET_H#include<QWidget>QT_BEGIN_NAMESPACEnamespaceUi{classWidget;}QT_END_NAMESPACEclassWidget:publicQWidget{Q_OBJECTpublic:Widget(QWidget*parent=nullptr);~Widget();......
  • SpringBoot基于Spring Security的HTTP跳转HTTPS
    简单说说之所以采用SpringSecurity来做这件事,一是SpringSecurity可以根据不同的URL来进行判断是否需要跳转(不推荐),二是不需要新建一个TomcatServletWebServerFactoryBean,新建这个Bean可能会导致SpringBoot关于Server的配置失效。三是网上大部分流传的通过实现WebServerFactor......
  • 如何在Spring Boot中记录用户系统操作流程?
    在现代Web应用程序中,记录用户系统操作流程对于监控用户行为、进行故障排查、安全审计等方面都是非常重要的。在本篇博客中,我们将介绍如何在SpringBoot中使用AOP(面向切面编程)和日志框架来实现用户系统操作流程的记录。1.介绍在大多数Web应用程序中,需要记录用户在系统中的操......
  • Storm实战——起步
    翻译自:GettingStartedWithStorm (作者:JonathanLeibiusky,GabrielEisbruch andDarioSimonassi)  在这一章,我们将动手创建一个Storm项目和第一个Stormtopology。  下面假定你已经安装了最新的Jre1.6。我们推荐使用Oracle提供的JRE,你可以在http://www.java.com/down......
  • 【Spring Boot 初识丨maven】
    上一篇讲了使用spirngboot自带的构建器构建项目本篇来讲一讲如何从零开始构建一个maven项目前提:jdk推荐java17及以上maven推荐Maven3.5+(maven构建)一、安装maven  Maven的安装需要依赖JDK的安装,所以必须先安装完成JDK且配置好JDK环境变量后在进行Maven的安装。......
  • SpringBoot+Vue实现校园二手系统。前后端分离技术【完整功能介绍+实现详情+源码】
    前言       这个系统基本上可以改造为其它类似的系统。后台管理基本上一致。前台进行一些页面样式的改造就可以变成一个新的系统。有时间,做几个变体系统。       闲的无聊,把大学时候做的一个系统进行了重构。将项目拆分成完全前后端分离的形式。客户端采用一套、商家......
  • python爬虫实战——小说爬取
    python爬虫实战——小说爬取基于requests库和lxml库编写的爬虫,目标小说网站域名http://www.365kk.cc/,类似的小说网站殊途同归,均可采用本文方法爬取。目标网站:传送门本文的目标书籍:《我的师兄实在太稳健了》“渡劫只有九成八的把握,和送死有什么区别?”基本思路网络爬虫的工作实际上主......
  • SpringBoot集成日志入门
    一、日志的作用程序中的日志是记录程序的运行情况,包括用户的各种操作、程序的运行状态等信息。类似于飞机的黑匣子。二、日志的级别表:日志级别及其描述日志级别描述OFF关闭:不输出日志FATAL致命:用于输出可能会导致应用程序终止的错误ERROR错误:用于输出程序的错误(这些错误不会导......