news 2026/3/21 14:18:43

SpEL 表达式详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpEL 表达式详解

SpEL表达式(Spring Expression Language)详解

SpEL(Spring Expression Language)是Spring框架提供的一种强大的表达式语言,用于在运行时查询和操作对象图,支持字面量、运算符、方法调用、属性访问、正则匹配、集合操作等,可独立使用或集成到Spring框架(如注解、XML配置、Bean定义)中。

一、核心特点

  1. 动态求值:运行时解析表达式,而非编译期;
  2. 跨场景使用:支持XML配置、注解(如@Value)、编程式调用;
  3. 丰富的语法:涵盖字面量、运算符、类型转换、集合操作、Bean引用等;
  4. 与Spring无缝集成:可直接访问Spring容器中的Bean、环境变量、系统属性等。

二、基本语法与常用场景

1. 字面量表达式

支持字符串、数字、布尔、null等基础类型的直接表达:

// 编程式调用示例(核心类:ExpressionParser、SpelExpressionParser、EvaluationContext)ExpressionParserparser=newSpelExpressionParser();// 字符串(单引号包裹)Expressionexp1=parser.parseExpression("'Hello SpEL'");Stringstr=(String)exp1.getValue();// 结果:Hello SpEL// 数字Expressionexp2=parser.parseExpression("100 + 200 * 2");intnum=(Integer)exp2.getValue();// 结果:500// 布尔Expressionexp3=parser.parseExpression("true && false");booleanbool=(Boolean)exp3.getValue();// 结果:false// nullExpressionexp4=parser.parseExpression("null");ObjectnullObj=exp4.getValue();// 结果:null

2. 属性与方法调用

通过.访问对象属性/方法,支持嵌套访问:

// 定义测试对象classUser{privateStringname;privateList<String>hobbies;publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicList<String>getHobbies(){returnhobbies;}publicvoidsetHobbies(List<String>hobbies){this.hobbies=hobbies;}publicStringsayHello(Stringmsg){return"Hello: "+msg;}}// 初始化上下文Useruser=newUser();user.setName("张三");user.setHobbies(Arrays.asList("篮球","读书"));EvaluationContextcontext=newStandardEvaluationContext(user);// 访问属性Stringname=(String)parser.parseExpression("name").getValue(context);// 张三// 调用方法(带参数)Stringhello=(String)parser.parseExpression("sayHello('SpEL')").getValue(context);// Hello: SpEL// 嵌套访问(集合属性)Stringhobby=(String)parser.parseExpression("hobbies[0]").getValue(context);// 篮球

3. 运算符

支持算术、逻辑、关系、赋值、三元运算符等:

类型运算符示例说明
算术10 + 23 * 410 % 3加减乘除、取模
逻辑`true
关系5 > 3'abc' == 'abc'大于、等于、不等于等
赋值name = '李四'为属性赋值
三元运算name == '张三' ? '是' : '否'条件判断
Elvis运算符name ?: '默认值'简化空判断(name为空则返回默认值)

示例:

// 三元运算Stringresult=(String)parser.parseExpression("name == '张三' ? '管理员' : '普通用户'").getValue(context);// 管理员// Elvis运算符(空保护)parser.parseExpression("name = null").getValue(context);StringdefaultName=(String)parser.parseExpression("name ?: '未知用户'").getValue(context);// 未知用户

4. 集合操作

支持访问集合元素、筛选、投影等:

// 1. 访问List/MapList<Integer>nums=Arrays.asList(1,2,3,4);EvaluationContextlistContext=newStandardEvaluationContext(nums);intfirst=(Integer)parser.parseExpression("[0]").getValue(listContext);// 1Map<String,Integer>map=newHashMap<>();map.put("a",10);map.put("b",20);EvaluationContextmapContext=newStandardEvaluationContext(map);intval=(Integer)parser.parseExpression("['b']").getValue(mapContext);// 20// 2. 集合筛选(.?[表达式])List<Integer>evenNums=(List<Integer>)parser.parseExpression(".?[#this % 2 == 0]").getValue(listContext);// [2,4]// 3. 集合投影(.![表达式])List<String>strNums=(List<String>)parser.parseExpression(".![#this + '号']").getValue(listContext);// [1号,2号,3号,4号]

5. Spring容器集成

(1)引用Spring Bean(@符号)

在Spring环境中,可直接引用容器中的Bean:

// 假设容器中有一个名为"userService"的Bean@Value("#{userService}")privateUserServiceuserService;// 调用Bean的方法@Value("#{userService.getUserName(1)}")privateStringuserName;
(2)访问环境变量/系统属性
// 系统属性(systemProperties)@Value("#{systemProperties['os.name']}")privateStringosName;// 例如:Windows 10// 环境变量(environment)@Value("#{environment['JAVA_HOME']}")privateStringjavaHome;// Spring配置属性(application.properties)@Value("#{my.properties['app.name']}")privateStringappName;

6. 注解中的常用场景

(1)@Value注解(区别:${}是占位符,#{}是SpEL)
// 基础值@Value("#{100 * 2}")privateintnum;// 200// 空判断@Value("#{user.name ?: '默认名称'}")privateStringuserName;// 集合@Value("#{T(java.util.Arrays).asList('a','b','c')}")privateList<String>letters;
(2)@PreAuthorize(Spring Security权限控制)
// 权限表达式(判断用户是否有指定角色)@PreAuthorize("#userId == authentication.principal.id or hasRole('ADMIN')")publicvoiddeleteUser(LonguserId){// 业务逻辑}

三、编程式使用SpEL的完整示例

importorg.springframework.expression.Expression;importorg.springframework.expression.ExpressionParser;importorg.springframework.expression.spel.standard.SpelExpressionParser;importorg.springframework.expression.spel.support.StandardEvaluationContext;publicclassSpELDemo{publicstaticvoidmain(String[]args){// 1. 创建表达式解析器ExpressionParserparser=newSpelExpressionParser();// 2. 定义上下文(绑定对象)Useruser=newUser();user.setName("李四");user.setAge(25);StandardEvaluationContextcontext=newStandardEvaluationContext(user);// 3. 解析表达式// 访问属性Stringname=(String)parser.parseExpression("name").getValue(context);System.out.println("姓名:"+name);// 李四// 运算 + 赋值parser.parseExpression("age = age + 1").getValue(context);intage=(Integer)parser.parseExpression("age").getValue(context);System.out.println("年龄:"+age);// 26// 方法调用Stringgreet=(String)parser.parseExpression("sayHello('SpEL')").getValue(context);System.out.println(greet);// Hello: SpEL}staticclassUser{privateStringname;privateintage;publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicintgetAge(){returnage;}publicvoidsetAge(intage){this.age=age;}publicStringsayHello(Stringmsg){return"Hello: "+msg;}}}

四、注意事项

  1. 性能:SpEL运行时解析,高频调用场景需缓存解析后的Expression对象;
  2. 安全:避免解析用户输入的表达式(防止注入攻击);
  3. 区别${}#{}
    • ${}:Spring占位符,仅做字符串替换(先解析);
    • #{}:SpEL表达式,支持动态求值(后解析);
    • 混合使用:@Value("${app.name:#{systemProperties['user.name']}}")(占位符默认值用SpEL);
  4. 类型转换:SpEL内置类型转换器,可自定义TypeConverter扩展。

五、核心API总结

类/接口作用
ExpressionParser表达式解析器(核心接口)
SpelExpressionParserExpressionParser的默认实现
EvaluationContext表达式求值上下文(绑定变量、Bean等)
StandardEvaluationContextEvaluationContext的默认实现
Expression解析后的表达式对象(可多次求值)

SpEL是Spring生态中灵活的动态表达式工具,核心场景包括配置注入、权限控制、动态规则判断等,掌握其语法可大幅提升Spring开发的灵活性。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/14 10:41:02

基于单片机的智能衣柜除湿与防霉系统设计【附代码】

&#x1f4c8; 算法与建模 | 专注PLC、单片机毕业设计 ✨ 擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导&#xff0c;毕业论文、期刊论文经验交流。 ✅ 专业定制毕业设计 ✅ 具体问题可以私信或查看文章底部二维码 本系统设计聚焦于为衣柜提供持续的防潮除…

作者头像 李华
网站建设 2026/3/21 7:10:21

Qwen3-VL-8B中文多模态实测:轻量高效,真正懂中文

Qwen3-VL-8B中文多模态实测&#xff1a;轻量高效&#xff0c;真正懂中文 在一家电商公司做技术负责人时&#xff0c;我曾被老板问过一个问题&#xff1a;“我们能不能让用户拍张图就推荐类似商品&#xff1f;就像小红书那样。”当时我们试了几个开源模型&#xff0c;结果不是回…

作者头像 李华
网站建设 2026/3/14 0:32:08

Flutter:在流动的 UI 中,重新理解“界面”的意义

Flutter&#xff1a;在流动的 UI 中&#xff0c;重新理解“界面”的意义 我们常说“用户界面”&#xff0c;仿佛界面是静态的、可切割的一层皮肤。但在 Flutter 的世界里&#xff0c;UI 是流动的、有生命的、由状态驱动的河流。 这不是一篇教你如何创建项目或使用 StatefulWi…

作者头像 李华
网站建设 2026/3/18 6:45:20

基于Dify部署多语言GPT-SoVITS合成系统的架构设计

基于Dify部署多语言GPT-SoVITS合成系统的架构设计 在智能语音技术快速演进的今天&#xff0c;个性化声音不再只是影视明星或大公司的专属资源。随着开源模型和低代码平台的成熟&#xff0c;普通人仅凭几分钟录音就能拥有“数字分身”的时代已经到来。尤其是在客服播报、有声内容…

作者头像 李华
网站建设 2026/3/21 13:47:00

LobeChat能否实现AI艺术品鉴定?收藏价值评估模型构建

LobeChat能否实现AI艺术品鉴定&#xff1f;收藏价值评估模型构建 在拍卖行的灯光下&#xff0c;一幅水墨虾蟹图静静陈列。专家俯身细看笔触走势、印章位置与纸张泛黄程度&#xff0c;几分钟后给出结论&#xff1a;“齐白石真迹&#xff0c;估价300万左右。”这样的场景正悄然发…

作者头像 李华
网站建设 2026/3/13 0:18:54

GPT-SoVITS训练过程中显存不足怎么办?优化建议

GPT-SoVITS训练显存不足&#xff1f;这5个实战优化策略让你在12GB显卡上跑起来 你有没有试过满怀期待地启动 GPT-SoVITS 训练&#xff0c;结果刚进第一个 epoch 就弹出 CUDA out of memory 的红色警告&#xff1f;别急&#xff0c;这不是你的数据有问题&#xff0c;也不是代码写…

作者头像 李华