Spring 中的动态表达式 SpEL
Spring 中的动态表达式艺术:SpEL
由浅入深、从应用到实战,逐步学习理解和掌握 Spring Expression Language。通过学习能够在实际开发过程中灵活应用、扩展以及排查和定位相关问题。
一. 先认眼熟,瞅瞅这玩意是个啥ʕ•̀ω•́ʔ✧
注意 EpEL 表达式以
#
开头。可以访问属性、调用属性支持的大部分方法、应用计算等
以下这种是属性占位符,以 $开头,不能包含 SpEL 表达式。里面只能包含 OGNL 表达式访问属性,不能调用方法。
介绍
Spring 表达式语言(简称“SpEL”)是一种强大的表达式语言,支持运行时查询和操作对象图。语法类似于 Jakarta 表达式语言,但提供了其他功能,最明显的是方法调用和基本字符串模板功能。而且可以独立使用,不过需要创建一些引导基础结构类,例如解析器。但是使用 Spring 环境是开箱即可食用。
表达式语言支持很多功能:诸如访问 字面量、属性、数组、列表、map、变量、方法、正则表达式、类型表示、字符串操作、Bean 访问等
关系运算符:and, or, not, &&, ||, !
逻辑运算符:<, >, ==, !=, <=, >=, lt, gt, eq, ne, le, ge
算数运算符:+, -, *, /, %, ^, div, mod、++、--
条件表达式:?:
二. 实际哪里会用到(•ө•)♡
配置文件中注入属性,比如使用 Spring 的 xml 配置、Springboot 的 @Value 中访问
在配置文件中使用它,ExcelUtils 是一个简单的工具类,里面有个静态的 get 方法.(注意调用非 Bean 的静态累的表达式语法是 T(xxx) )
在 Springboot 中使用它
依赖注入和按条件配置,比如上面的
@ConditionalOnExpression("#{${business.maxCount:0} gt 0}")
这一段,就表示${business.maxCount:0}
这个属性的类型必须是int
(必须是数值类型),gt
表示同时它的值必须大于 0,满足条件才会创建对应的 Bean换一个姿势,诸如 Bean 的时候按照表达式解析动态传入数据:
SpEL 在 AOP 中的应用:
常见的 Spring 框架内置的支持 SpEL 的有:@Value、@ConditionalOnExpression、@ConditionalOnProperty<本身基于属性,但我们可以使用 SpEL 做增强判断等>、Spring Data JPA 的查询、Spring Security 中的表达式等。其他一些基于 Spring 的扩展也会支持 SpEL。
三. 都有哪些使用姿势,支持哪些操作解析,有何限制( ◠‿◠ )
直接在 Spring 中使用表达式获取符号 #{}操作符来操作元素。如 第一部分展示的那样。
使用 SpEL API 来手动编写解析,使用内置的解析器和处理器。
支持的功能列表:
局限性:SpEL 内置 SpEL Compilation 对表达式进行解释、编译,但不是所有类型的表达式都支持编译。主要关注的是可能在性能关键上下文中使用的常用表达式。无法编译的比如涉及赋值的表达式、自定义解析器或者访问器的表达式、使用重载运算符的表达式、使用数组构造语法的表达式、使用选择或投影的表达式。什么意思呢,其实就是说这些表达式不支持编译运行,这些表达式的性能就不如其他的可编译执行的表达式性能好。和我们 JVM 的编译执行、解释执行一个道理,各有千秋。
它是一个强大的表达式语言,用来做一些基于配置的动态判断,不复杂的逻辑判断等,不是让编程人员在 SpEL 里面去写业务逻辑或者复杂操作的,应当避免这种行为。
一般来说,应该避免在 SPEL 表达式中包含用户输入。如果用户输入必须包含在表达式中,那么应该在有限的上下文中进行计算,不允许任意调用方法。【避免使用表达式攻击系统】
四. 还可以手动调用(´◔౪◔)ʃ
五. 噢哟,不错哦!它怎么做到的呢(✿╹◡╹)
解析的总体过程如下:
SimpleevalationContext 被设计为仅支持 SpEL 语言语法的一个子集。它排除了 Java 类型引用、构造函数和 bean 引用。它还要求显式地选择对表达式中的属性和方法的支持级别。默认情况下,create ()静态工厂方法只允许对属性进行读访问。StandardEvaluationContext 是完整版的支持,公开全套 SpEL 语言特性和配置选项。可以使用它来指定默认的根对象,并配置每个可用的计算相关策略。(Bean 的引用默认实现使用 JavaBean 约定)
默认情况下,SpEL 使用 Spring 核心中提供的转换服务(org.springframework.core.Convert)。此转换服务附带了许多用于常见转换的内置转换器。此外,它还支持泛型。这意味着,在表达式中处理泛型类型时,SpEL 尝试转换来维护它遇到的任何对象的类型正确性
通过 conversionService.canConvert(sourceTypeDesc, typeDescriptor)来判断是否能将源数据类型转换为目标类型,比如最常见的就是 String 转为 int(使用的 StringToNumberConverterFactory 中的静态内部类 StringToNumber)(使用 NumberUtils.parseNumber 方法)
内置的类型转换器都在 spring-core 核心包的 org.springframework.core.convert 包里面。表达式的定义和解析在 spring-expression 包中。
六. 类似的表达式语言还蛮多哟(๑◔‿◔๑)
Java 表达式语言(OGNL、MVEL 和 JBoss EL 等){不要忘记我们刚开始后端写 jsp 经常用到的 EL 表达式哦,由 web 容器实现并解析和展示,比如我们经常内置 Tomcat 就会看到 tomcat-embed-el-xxx.jar,独立的 Tomcat 在 lib 目录里面的 jasper-el.jar,就是用来把我们在 jsp 页面上写的表达式经过 japer-el 引擎转为字面量展示}
点这里看SpEL官网内容介绍
版权声明: 本文为 InfoQ 作者【豆芽发达咯】的原创文章。
原文链接:【http://xie.infoq.cn/article/c46e53b2aa5ca04c7d42e9b52】。文章转载请联系作者。
评论