type
Post
status
Published
date
Nov 16, 2022
slug
summary
tags
Java
category
技术分享
icon
password
Property
Apr 4, 2023 08:58 AM
Spring Expression Language(简称SpEL)是一种强大的表达式语言,支持在运行时查询和操作对象图。语言语法类似于Unified EL,但提供了额外的功能,特别是方法调用和基本的字符串模板功能。同时因为SpEL是以API接口的形式创建的,所以允许将其集成到其他应用程序和框架中。
Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系,而SpEl可以方便快捷的对ApplicationContext中的Bean进行属性的装配和提取。
环境demo
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.3.15</version> </dependency> </dependencies>
package spel; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; public class demo{ public static void main(String[] args) { ExpressionParser parser = new SpelExpressionParser(); Expression exp = parser.parseExpression("T(java.lang.Runtime).getRuntime().exec(\"calc.exe\")"); Object value = exp.getValue().toString(); } }
调用链分析
获取解析器配置
ExpressionParser parser = new SpelExpressionParser() 后
SpelExpressionParser中的configuration存放的是SpEL表达式解析器的配置选项,包括自定义函数、变量和类型注册等选项。这些配置选项可以用来扩展表达式语言的功能,使其能够更好地满足应用程序的需求。例如,可以使用配置选项向表达式语言中添加自定义函数,以便在表达式中调用自定义逻辑。
初始化spel解析对象
接着来到获取Expression对象并将spel表达式填入,在
new SpelExpression(expressionString, ast, this.configuration)将结合我们给的表达式和解析器配置信息返回一个已经初始化好的SpelExpression对象
此前的调用栈如下:
doParseExpression:138, InternalSpelExpressionParser (org.springframework.expression.spel.standard) doParseExpression:61, SpelExpressionParser (org.springframework.expression.spel.standard) doParseExpression:33, SpelExpressionParser (org.springframework.expression.spel.standard) parseExpression:52, TemplateAwareExpressionParser (org.springframework.expression.common) parseExpression:43, TemplateAwareExpressionParser (org.springframework.expression.common) main:10, demo (spel)
执行spel表达式
Object value = exp.getValue()先通过
ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration); 创建获取一个新的表达式状态实例对象
步入下一段代码,
Object result = this.ast.getValue(expressionState);这里调用了SpelExpression对象的ast属性(CompoundExpression对象)的getValue方法,并传入ExpressionState对象。持续步入到
getValueRef:61, CompoundExpression (org.springframework.expression.spel.ast) 可以看到其中有个循环遍历this.children数组,拿到数组中的getRuntime等(记住这个遍历)
步入至
getValueInternal:103, MethodReference (org.springframework.expression.spel.ast)并传入以下四个参数
接下来来到个次重点的地方,
findAccessorForMethod:202, MethodReference (org.springframework.expression.spel.ast) 该方法用于SpEL解析对象属性表达式时可引用、调用给定的类、方法和参数类型所匹配的方法,将返回的MethodExecutor对象赋给executorToUse

最后跟进到
executorToUse.execute(evaluationContext, value, arguments); 最后通过反射调用getRuntime的exec方法实现命令执行
此前的调用栈为:
execute:130, ReflectiveMethodExecutor (org.springframework.expression.spel.support) getValueInternal:139, MethodReference (org.springframework.expression.spel.ast) access$000:55, MethodReference (org.springframework.expression.spel.ast) getValue:387, MethodReference$MethodValueRef (org.springframework.expression.spel.ast) getValueInternal:92, CompoundExpression (org.springframework.expression.spel.ast) getValue:112, SpelNodeImpl (org.springframework.expression.spel.ast) getValue:141, SpelExpression (org.springframework.expression.spel.standard) main:11, demo (spel)
小结
SpEL表达式的命令注入命令执行实际上也用反射去获取Class对象、methodToInvoke方法和arguments执行参数,最后还是用反射的invoke方法去执行命令
- Author:w1nk1
- URL:https://notion-w1nk1.vercel.app//article/482a04ec-b9ba-440e-ba25-4160274c06d0
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts