Spring EL表达式原来都是配合这些类一起使用的

这里是weihubeats,觉得文章不错可以关注公众号小奏技术,文章首发。拒绝营销号,拒绝标题党

Spring EL表达式可以干什么

我们最常见的一些开源框架就经常会在注解中获取方法参数的值。

比如spring cache

    @GetMapping("/test")
    @Cacheable(cacheNames = "student", key = "#name")
    public  List<StudentVO> test(String name) {
        return mockSelectSql();
    }

这里的 #name就是EL表达式。代表获取入参name的值

今天我们就来探究下SpringEL表达式

Spring EL表达式的解析器 SpelExpressionParser

spring中实现EL表达式的解析器就是SpelExpressionParser这个类

使用也非常简单。我们通过下面的几个用例来了解一下

SpelExpressionParser parser = new SpelExpressionParser();
		String value = parser.parseExpression("'xiaozou'").getValue(String.class);//  ,注意string有单引号包裹
		Long value1 = parser.parseExpression("1.024E+3").getValue(Long.class);// 1024  , 指数形式
		Integer value2 = parser.parseExpression("0x208").getValue(Integer.class);// 520 十六进制  0x208
		Boolean value3 = parser.parseExpression("true").getValue(Boolean.class);// true
		Object value4 = parser.parseExpression("null").getValue();
		System.out.printf("value: %s\n value1: %s\n value2: %s\n value3: %s\n value4: %s\n", value, value1, value2, value3, value4);

对字符串和一些普通数字的解析好像没什么用。实际业务场景我也用不到。

对对象属性进行获取

SpelExpressionParser还可以获取对象的属性,比如向如下

ExpressionParser parser = new SpelExpressionParser();
		Expression expression = parser.parseExpression("name");
		Person person = new Person("xiaozou");
		String result = expression.getValue(person, String.class);
		System.out.println(result); // Output: xiaozou

方法调用

ExpressionParser parser = new SpelExpressionParser();
		Expression expression = parser.parseExpression("toUpperCase()");
		String str = "xiaozou";
		String result = expression.getValue(str, String.class);
		System.out.println(result); // Output: XIAOZOU

EL上下文 StandardEvaluationContext

当使用SpEL时,可以结合StandardEvaluationContext来设置根对象、变量和函数。

这样我们每次使用ExpressionParser就无需传入具体的对象,只从StandardEvaluationContext上下文中获取即可,实际spring中的一些EL表达式的实际使用都是结合StandardEvaluationContext使用的。

这里我们也来看一些使用用例

// 创建 SpelExpressionParser 实例
		SpelExpressionParser parser = new SpelExpressionParser();
		// 创建 StandardEvaluationContext 实例
		StandardEvaluationContext context = new StandardEvaluationContext();

		// 在上下文中设置变量
		context.setVariable("name", "John");
		context.setVariable("age", 30);

		// 解析表达式并计算结果
		Expression expression = parser.parseExpression("'Hello, ' + #name + '! You are ' + #age + ' years old.'");
		String result = expression.getValue(context, String.class);
        // 输出结果 Hello, xiaozou! You are 18 years old.
		System.out.println(result);

这种是直接放入常量,我们也可以放入对象

  ExpressionParser parser = new SpelExpressionParser();
		Expression expression = parser.parseExpression("name");
		Person person = new Person("xiao zou");
		StandardEvaluationContext context = new StandardEvaluationContext(person);
		String result = expression.getValue(context, String.class);
		System.out.println(result); // Output: xiaozou

Spring 参数解析器

从上面的很多个例子中我们可以看到Spring EL可以获取对象的属性,我们在解析对象的时候一般会要对象的变量名。

也是就SpringAOP中通过EL 表达式获取方法的参数的时候是需要参数名的,那么我们如何获取方法的参数名呢。

Spring提供了ParameterNameDiscoverer接口。
我们看看ParameterNameDiscoverer接口的实现类有哪些?

可以看到有非常多,比较常用的就是LocalVariableTableParameterNameDiscovererDefaultParameterNameDiscoverer.

LocalVariableTableParameterNameDiscoverer是一种基于本地变量表的参数解析器,依赖于编译时的选项,可能无法在所有情况下获取参数名称。而DefaultParameterNameDiscoverer是一个更通用的参数解析器,尝试多种策略来获取参数名称,能够在更广泛的情况下获取到参数名称,但是效率相对会低一点。

一般使用LocalVariableTableParameterNameDiscoverer 即可

这里我以一个简单的例子来看看

@Test
	public void testParameterNameDiscoverer() throws Exception{
		ParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
		Method method = MyClass.class.getMethod("myMethod", String.class, int.class);
		String[] parameterNames = discoverer.getParameterNames(method);
		for (String parameterName : parameterNames) {
			System.out.println("parameterName " + parameterName);// out  parameterName name parameterName age
		}
	}
	
	@Data
	static class MyClass {
		private String name = "Default";
		private int age = 0;
		public void myMethod(String name, int age) {
			// Method body
		}
	}

ExpressionParser+StandardEvaluationContext+ParameterNameDiscoverer

一般我们在使用Spring EL表达式的时候我们都会结合这三个类来使用。

比如我们写一个EL表达式的工具类

/**
     * el表达式解析
     *
     * @param expressionString 解析值
     * @param method           方法
     * @param args             参数
     * @return
     */
    public static Object parse(String expressionString, Method method, Object[] args) {
        if (DataUtils.isEmpty(expressionString)) {
            return null;
        }
        //获取被拦截方法参数名列表
        LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] paramNameArr = discoverer.getParameterNames(method);
        //SPEL解析
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < Objects.requireNonNull(paramNameArr).length; i++) {
            context.setVariable(paramNameArr[i], args[i]);
        }
        return parser.parseExpression(expressionString).getValue(context);
    }

我们通过LocalVariableTableParameterNameDiscoverer解析方法的参数名字

然后将方法名和参数方法StandardEvaluationContext上下文中,然后通过EL解析器SpelExpressionParser去获取value

Spring cache 中EL表达式中的使用

实际Spring cache中也实现了自己的EL表达式解析

我们可以简单看看。核心实现类是CacheOperationExpressionEvaluator

CacheOperationExpressionEvaluator继承了一个抽象类CachedExpressionEvaluator

然后CachedExpressionEvaluator中就有具体的EL表达式的一些功能实现,包括我们之前提到的参数解析器ParameterNameDiscoverer,然后就是EL表达式解析的核心实现类SpelExpressionParser

其实我们可以看到EL表达式的组合拳三者已显其二,还有一个EvaluationContext在哪呢?

实际是在方法generateKey中去创建的。我们来看看源码


可以看到在这里就创建了一个EvaluationContext,这里的上下文也是Cache模块自己实现一个类CacheEvaluationContext

具体放了个啥呢?实际就放了一个返回结果

总结

本次我们详细的分析了Spring EL表达式中SpelExpressionParser的一些核心用法。以及实际使用中是如何结合ParameterNameDiscovererEvaluationContext去使用的。

简单实现了一个EL表达式的工具类,也结合Spring cache模块的EL表达式进行了简单的源码分析。

让大家对Spring EL表达式有全面的了解

测试源码地址

  • 源码:https://github.com/weihubeats/weihubeats_demos/blob/master/spring-boot-demos/spring-boot-base/src/test/java/SpringTest.java

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/144163.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mysql 中with的用法(1)

mysql 中with的用法 1、案例一&#xff1a; 建表&#xff1a; CREATE TABLE employees (employee_id INT PRIMARY KEY,first_name VARCHAR(50),last_name VARCHAR(50),salary INT );INSERT INTO employees (employee_id, first_name, last_name, salary) VALUES (1, John, Do…

20-90V输入 降压12V 3A 外置MOS 大电流降压芯片

20-90V输入 降压12V 3A 外置MOS 大电流降压芯片

【运维】-- 在线网络工具

1、https://ping.pe/ 一个免费的在线网络工具&#xff0c;可以帮助您检测和分析IP地址的连接情况。 这是搬瓦工官方做的一个 ping 在线测试网站工具。比较适合测试短时间的 ping 统计&#xff0c;并且在网页上以图表形式统计显示出来。 PS&#xff1a; a、丢包会以红色显示出…

(八)Spring源码解析:Spring MVC

一、Servlet及上下文的初始化 1.1> DispatcherServlet的初始化 对于Spring MVC来说&#xff0c;最核心的一个类就是DispatcherServlet&#xff0c;它负责请求的行为流转。那么在Servlet的初始化阶段&#xff0c;会调用init()方法进行初始化操作&#xff0c;在DispatcherSe…

arcgis--二维点、线转三维

利用【3D Analyst工具】-【3D要素】-【依据属性实现要素转3D】将点要素转换成三维点。二维点属性中需含有其点高程信息。原始输入数据点属性表如下&#xff1a; 利用【依据属性实现要素转3D】工具&#xff0c;将其转成三维点。参数设置如下&#xff1a; 点转三维后&#xff0c;…

一个非常基础的python函数语法:lambda表达式

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 lambda表达式本身是一个非常基础的python函数语法&#xff0c;其基本功能跟使用def所定义的python函数是一样的&#xff0c; 只是lambda表达式基本在一行以内就完…

使用后端代码生成器,提高开发效率

如果你是一名后端开发者&#xff0c;那么大多数的工作一定是重复编写各种 CRUD&#xff08;增删改查&#xff09;代码。时间长了你会发现&#xff0c;这些工作不仅无趣&#xff0c;还会浪费你的很多时间&#xff0c;没有机会去做更有创造力和挑战的工作。 作为一名程序员&…

基于C++设计与实现的算符优先分析器

一、实验目的及要求 1.1 目的 加深对语法分析器工作过程的理解&#xff1b;加强对算符优先分析法实现语法分析程序的掌握&#xff1b;能够采用一种编程语言实现简单的语法分析程序&#xff1b;能够使用自己编写的分析程序对简单的程序段进行语法翻译。 1.2 要求 对语法规则…

单链表OJ题目——C语言

本篇博客并非提供完整解题思路代码&#xff0c;而是重点阐述在OJ的链表题目中容易被忽视的点&#xff0c;从而让部分读者在出错百思不得解的情况下能快速发现自己的漏洞&#xff0c;高效查缺补漏&#xff0c;本博客支持读者按题搜索&#xff0c;同时也支持读者根据博客内容自行…

安装pr缺少wmvcore.dll的解决方法,分享4个有效的方法

在当今数字化时代&#xff0c;计算机软件在我们的生活中扮演着重要的角色。然而&#xff0c;有时候我们可能会遇到一些软件问题&#xff0c;其中之一就是缺少某个关键的动态链接库文件。在这篇文章中&#xff0c;我将分享关于如何解决Adobe Premiere Pro&#xff08;PR&#xf…

【官宣】守护四年,“惠医保”暖心回归!

11月13日&#xff0c;惠州参保人专属的城市定制型商业健康险——“惠医保2024”正式升级上线&#xff0c;面向全市基本医保参保人开放参保&#xff0c;超200万保障&#xff0c;150元/人/年起&#xff01; 惠州市医疗保障局、惠州市卫生健康局、惠州市金融工作局及国家金融监督…

c#桥接模式详解

基础介绍&#xff1a; 将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。适用于不希望在抽象和实现部分之间有固定的绑定关系的情况&#xff0c;或者类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充的情况。 将抽象部分与实现部分分离&#xff0c;…

C语言中自己实现了一个排序为什么会比 qsort 的速度慢几十倍不止

C语言中自己实现了一个排序&#xff0c;为什么会比 qsort 的速度慢几十倍不止? 讲到算法&#xff0c;有一个非常重要的前置知识叫时间复杂度&#xff0c;脱离了这个讲算法的优劣是没什么意义的。这个概念主要是指&#xff0c;你数据量的增加&#xff0c;会让算法的处理时间增加…

mini型光学3D表面轮廓仪,上车即走,上桌即用!

“小身材&#xff0c;大作用”——一个简单的比喻&#xff0c;恰当地总结了SuperView WM100光学3D表面轮廓仪的特点。mini型光学3D表面轮廓仪SuperView WM100&#xff0c;回应了市场对小型化、便携式光学3D表面轮廓仪的需求。 轻便的机身&#xff0c;简约的设计——没有控制箱…

element el-upload上传功能

2023.11.14今天我学习了如何使用el-upload: <!--drag设置可拖动--><!--accept".xlsx"设置上传的文件类型--><!--:limit1上传文件的最大个数--><!--:auto-upload"false"是否在选取后直接上传--><!--:before-upload"beforeU…

cout的输出整数格式

cout默认以十进制格式显示整数 cout << oct和cout << hex不会显示出来&#xff0c;而只是修改cout显示整数的方式 使用std::hex和std::oct时&#xff0c;可以将hex和oct当做变量名&#xff0c;否则不可以 #include<iostream>int main() {int a;std::cout &l…

高并发场景下,如何设计订单库存架构,一共9个关键性问题

库存系统可以分为实物库存和虚拟库存两种类型。实物库存的管理涉及到采购、存储、销售和库存轮换等复杂的活动&#xff0c;需要进行供应链管理和仓库管理等工作。相比之下&#xff0c;虚拟库存的管理相对简单&#xff0c;主要适用于线上资源的数量管理&#xff0c;包括各类虚拟…

安装部署Esxi7.0并创建虚拟机

1. Esxi介绍 ESXI虚拟平台是VMware出品的一个强大平台&#xff0c;它可以直接安装在物理机上&#xff0c;从而充分利用物理奖性能&#xff0c;虚拟多个系统出来。ESXI是一个带WEB管理后台的软件&#xff0c;非常适合安装在服务器上&#xff0c;然后直接通过网页进行远程管理。…

发布自研大模型 夸克App将迎来全面升级

国产大模型阵营再添新锐选手。11月14日&#xff0c;阿里巴巴智能信息事业群发布全栈自研、千亿级参数的夸克大模型&#xff0c;将应用于通用搜索、医疗健康、教育学习、职场办公等众多场景。夸克App将借助自研大模型全面升级&#xff0c;加速迈向年轻人工作、学习、生活的AI助手…

分享一下微信会员充值管理系统怎么做

在当今数字化时代&#xff0c;微信作为中国最流行的社交平台&#xff0c;其功能已经从简单的沟通交流扩展到了生活的方方面面。微信会员充值管理系统就是其中之一&#xff0c;它为商家提供了一个高效、便捷的充值体验&#xff0c;同时也为用户提供了更加个性化的服务。本文将详…