行业网站建设凯里网站建设

杭州多诚消防技术有限公司 2026/09/09 18:32:17

在SpringBoot开发中,我们经常会遇到需要动态获取配置、动态调用方法、动态判断条件的场景。而SpEL(Spring Expression Language,Spring表达式语言)就是Spring提供的一款强大的“动态工具”,能帮我们轻松搞定这些需求。

很多小伙伴对SpEL的了解还停留在“听过但不会用”的阶段,今天这篇文章就从基础到实战,把SpEL讲透,配合具体代码示例,让你看完就能上手!

一、什么是SpEL?

SpEL是Spring框架自带的表达式语言,支持运行时查询和操作对象,功能非常强大。它和JSP的EL表达式有点类似,但适用范围更广——不仅能在配置文件中使用,还能在Java代码、注解中使用。

核心作用:动态求值。比如动态获取配置项、动态调用Bean的方法、动态访问对象的属性等。

举个简单的例子,我们想在代码中动态获取application.yml中的配置值,用SpEL可以直接写:@Value("${spring.datasource.url}"),这就是SpEL最基础的用法之一。

二、SpEL基础语法

SpEL的表达式以#{}包裹(注意和EL表达式的${}区分,后者主要用于配置占位符,而SpEL可以做更复杂的运算),内部支持多种语法:

1. 字面量表达式

直接表示基本数据类型、字符串等,简单直观:

#{100}// 整数#{3.14}// 浮点数#{true}// 布尔值#{'HelloSpEL'}// 字符串(单引号包裹)

2. 变量引用

使用#变量名引用变量,常见于代码中或Spring内置变量:

  • #root:根对象

  • #this:当前对象

  • #systemProperties:系统属性(Spring内置)

  • #environment:环境变量(Spring内置,可获取配置文件值)

示例:获取系统属性中的Java版本

#{systemProperties['java.version']}

3. 运算符表达式

支持算术运算、比较运算、逻辑运算、三元运算等,和Java语法类似:

#{10+20}// 算术运算:30#{100>50}// 比较运算:true#{true&&false}// 逻辑运算:false#{age>18?'成年':'未成年'}// 三元运算

4. 方法调用

可以直接调用对象的方法,包括静态方法和实例方法:

#{'Hello'.toUpperCase()}// 实例方法:HELLO#{Math.abs(-100)}// 静态方法:100(Math是全类名,可省略全类名需配置)

5. 集合操作

支持对List、Map等集合的创建和访问:

#{['a','b','c']}// 创建List#{{'name':'张三','age':20}}// 创建Map(注意大括号内键值对)#{['a','b','c'][0]}// 访问List索引:a#{{'name':'张三','age':20}['name']}// 访问Map键:张三

三、SpringBoot中SpEL的核心用法场景

SpEL在SpringBoot中的应用非常广泛,最常用的有以下4个场景,每个场景都配了可直接运行的代码示例~

场景1:@Value注解中动态注入值

这是最常用的场景!通过@Value配合SpEL,可动态注入配置值、系统属性、运算结果等,替代硬编码。

步骤:

  1. 在application.yml中定义配置:
user:name:李四age:25address:北京-朝阳区max-score:100
  1. 在Bean中用@Value + SpEL注入:
importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;@ComponentpublicclassUserConfig{// 1. 注入配置文件中的值(结合${}占位符,SpEL可嵌套${})@Value("#{${user.age}}")privateIntegerage;// 2. 注入配置值并做运算@Value("#{${user.max-score} * 0.8}")// 100 * 0.8 = 80privateDoublepassScore;// 3. 注入字符串并拼接@Value("#{'用户姓名:' + '${user.name}'}")privateStringuserName;// 4. 注入系统属性@Value("#{systemProperties['os.name']}")privateStringosName;// 5. 三元运算动态注入@Value("#{${user.age} > 18 ? '成年用户' : '未成年用户'}")privateStringuserType;// getter/setter省略}}

测试:启动项目,获取UserConfig Bean,打印属性值,会发现所有值都被正确注入~

场景2:@ConditionalOnExpression条件注解

在SpringBoot自动配置中,经常用@ConditionalOnExpression配合SpEL实现“动态条件装配Bean”——只有当SpEL表达式求值为true时,才创建该Bean。

示例:根据配置文件中的feature.redis.enable值,决定是否创建RedisTemplate Bean:

importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Conditional;importorg.springframework.context.annotation.Configuration;importorg.springframework.boot.autoconfigure.condition.ConditionalOnExpression;importorg.springframework.data.redis.core.RedisTemplate;@ConfigurationpublicclassRedisConfig{// 当配置项feature.redis.enable为true时,才创建该Bean@Bean@ConditionalOnExpression("#{environment.getProperty('feature.redis.enable') == 'true'}")publicRedisTemplate<String,Object>redisTemplate(){RedisTemplate&lt;String,Object&gt;template=newRedisTemplate<>();// 配置RedisTemplate(省略连接工厂等配置)returntemplate;}}

说明:environment.getProperty('key')用于获取配置文件中的值,表达式结果为true时,Bean才会被装配。

场景3:Spring Security中的权限控制

在Spring Security中,可通过SpEL动态判断用户权限,比如在@PreAuthorize注解中使用,控制方法的访问权限。

示例:只有拥有ADMIN角色或用户ID为1的用户,才能访问deleteUser方法:

importorg.springframework.security.access.prepost.PreAuthorize;importorg.springframework.web.bind.annotation.DeleteMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassUserController{// SpEL表达式:hasRole('ADMIN')判断角色,authentication.principal获取当前用户@PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")@DeleteMapping("/user/{userId}")publicStringdeleteUser(@PathVariableIntegeruserId){// 删除用户逻辑return"删除成功";}}

常用的Spring Security SpEL表达式:

  • hasRole('角色名'):是否拥有指定角色

  • hasAuthority('权限名'):是否拥有指定权限

  • authentication:当前认证对象

  • principal:当前用户对象

场景4:代码中直接使用SpEL求值

除了注解,我们还可以在Java代码中直接创建SpEL解析器,手动解析表达式,灵活处理复杂场景。

核心API:

  • ExpressionParser:表达式解析器,常用实现SpelExpressionParser

  • Expression:解析后的表达式对象,调用getValue()求值

  • EvaluationContext:求值上下文,用于定义变量、根对象等

示例1:解析简单表达式

importorg.springframework.expression.Expression;importorg.springframework.expression.ExpressionParser;importorg.springframework.expression.spel.standard.SpelExpressionParser;publicclassSpelDemo{publicstaticvoidmain(String[]args){// 1. 创建解析器ExpressionParserparser=newSpelExpressionParser();// 2. 解析表达式(求10+20*3的结果)Expressionexpression=parser.parseExpression("10 + 20 * 3");// 3. 求值Integerresult=expression.getValue(Integer.class);System.out.println(result);// 输出70}}

示例2:操作对象属性和方法

importorg.springframework.expression.Expression;importorg.springframework.expression.ExpressionParser;importorg.springframework.expression.spel.standard.SpelExpressionParser;importorg.springframework.expression.spel.support.StandardEvaluationContext;// 定义用户类classUser{privateStringname;privateIntegerage;// getter/setter/构造方法省略publicStringgetUserName(){return"用户:"+name;}}publicclassSpelObjectDemo{publicstaticvoidmain(String[]args){ExpressionParserparser=newSpelExpressionParser();StandardEvaluationContextcontext=newStandardEvaluationContext();// 1. 定义根对象Useruser=newUser("张三",25);context.setRootObject(user);// 2. 解析表达式:获取根对象的name属性Expressionexp1=parser.parseExpression("name");Stringname=exp1.getValue(context,String.class);System.out.println(name);// 输出张三// 3. 解析表达式:调用根对象的getUserName()方法Expressionexp2=parser.parseExpression("getUserName()");StringuserName=exp2.getValue(context,String.class);System.out.println(userName);// 输出用户:张三// 4. 解析表达式:给age属性赋值Expressionexp3=parser.parseExpression("age = 30");exp3.getValue(context);System.out.println(user.getAge());// 输出30}}

四、SpEL使用注意事项

  1. 区分 #{}${}

    • ${}:用于配置占位符,只能获取配置值,不能做运算;

    • #{}:SpEL表达式,支持运算、方法调用等复杂操作;

    • 嵌套使用:如果需要对配置值做运算,可以嵌套,比如#{${user.age} + 5}

  2. 避免复杂表达式:SpEL虽然强大,但如果表达式过于复杂(比如多层嵌套、复杂逻辑),会降低代码可读性,建议复杂逻辑放在Java代码中实现。

  3. 空指针问题:使用SpEL访问对象属性或调用方法时,要确保对象不为null,否则会抛出空指针异常,可通过三元运算规避:#{user != null ? user.name : '默认值'}

  4. 性能问题:频繁创建ExpressionParser会影响性能,建议将其定义为单例复用。

五、总结

SpEL是SpringBoot中的“动态利器”,核心用于动态求值,常见场景包括:

  • @Value注解动态注入;

  • @ConditionalOnExpression条件装配;

  • Spring Security权限控制;

  • 代码中手动解析表达式。

掌握SpEL的基础语法和核心场景,能让你的代码更灵活、更简洁。建议大家结合文中的示例代码动手实践一下,很快就能上手~

如果这篇文章对你有帮助,别忘了点赞、在看、转发三连哦!有任何问题,欢迎在评论区留言~

咱们下期再见!👋

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

电器网站建设建设企业网站

Typora 1.9.5:5大亮点让你爱上这款高效Markdown编辑器【免费下载链接】Typora1.9.5Windows版本下载本仓库提供 Typora 1.9.5 版本的 Wind

2026/06/30 10:16:19

汕头网站建设网站建设分析

Android开发效率革命:RxTool工具库的完整实践指南【免费下载链接】RxTool项目地址: https://gitcode.com/gh_mirrors/rxt/RxTool在A

2026/06/30 12:05:59

广州网站建设漳州网站建设

特殊儿童关爱:为孤独症儿童定制沟通训练语音在一间安静的康复教室里,老师正耐心地引导一名孤独症儿童完成“指认颜色”的任务。屏幕上出现一个红色圆形,紧接着响起温和

2026/06/30 13:38:06

寿光网站建设荆州网站建设

?关注我? 教程每日多更,一起学习!更多免费教程和软件 :​?关注我? 教程每日多更,一起学习!多维尺度分析多维尺度分析(MultiDimensional Scaling)是分析研究对象的相

2026/06/30 11:43:57

网站建设与维护上海网站建设公司

使用VSCode插件加速EmotiVoice开发:高效调试文本转语音流程在虚拟偶像直播中突然出现机械音,或是游戏NPC对话听起来像念稿——这些体验背后,往往是

2026/06/30 14:12:09

网站建设与维护滨州网站建设

快速体验打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容:开发一个高性能生肖买马游戏系统,要求:1. 支持

2026/06/30 13:36:06

广州建设网站公司网站建设方案

型号介绍今天我要向大家介绍的是TDK的一款滤波器——DEA162500LT-1212A1。 它一旦遇到那些试图“闯入”的更高频率的杂波,比如4800-5000MHz的信号,

2026/06/30 14:10:39

网站建设中镇江网站建设

快速体验打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容:构建一个最小可行的共享库检测原型,要求:1. 接

2026/06/30 11:13:54

广州网站建设省建设厅网站

Navicat Premium Mac版无限重置试用期终极指南 🚀【免费下载链接】navicat_reset_macnavicat16 mac版无限重置试用期脚本项目地址: https

2026/06/30 13:36:36

网站外链建设app网站建设

药店管理目录基于springboot + vue药店管理系统一、前言二、系统功能演示三、技术选型四、其他项目参考五、代码参考六、测试参考七、最新计算机毕设选题推荐八、源码获取:基

2026/06/30 12:50:03