目录

一、SpEL是什么?为什么需要它?

核心价值:

典型应用场景:

二、基础语法快速入门

1. 表达式解析基础

2. 字面量表示

3. 属性访问

三、SpEL核心特性详解

1. 集合操作

2. 方法调用

3. 运算符大全

4. 类型操作

四、Spring集成实战

1. XML配置中的SpEL

2. 注解配置中的SpEL

3. Spring Data中的SpEL

五、高级技巧与最佳实践

1. 自定义函数扩展

2. 模板表达式

3. 安全沙箱限制

六、性能优化指南

1. 表达式编译

2. 缓存策略

3. 避免性能陷阱

七、SpEL在Spring生态系统中的应用

1. Spring Security

2. Spring Integration

3. Spring Batch

八、总结:SpEL最佳实践


一、SpEL是什么?为什么需要它?

Spring Expression Language (SpEL) 是Spring框架3.0引入的动态表达式引擎,它允许在运行时查询和操作对象图。与OGNL和MVEL类似,但深度集成Spring生态。

核心价值:

典型应用场景:

  1. Spring XML/注解配置中的动态值

  2. Spring Security的权限表达式

  3. Spring Data的查询方法

  4. Thymeleaf模板引擎

  5. @Value注解注入

二、基础语法快速入门

1. 表达式解析基础

ExpressionParser parser = new SpelExpressionParser();// 数学运算
Expression exp = parser.parseExpression("100 * 2 + 50");
Integer result = (Integer) exp.getValue();  // 250// 字符串操作
exp = parser.parseExpression("'Hello ' + 'World'");
String str = exp.getValue(String.class);  // "Hello World"

2. 字面量表示

类型示例
整型420x2A
浮点型3.146.022e23
布尔型truefalse
字符串'Single Quote'
Nullnull

3. 属性访问

public class User {private String name;private Address address;// getters
}// 链式属性访问
exp = parser.parseExpression("address.city");
String city = exp.getValue(user, String.class); // 获取user.address.city
 

三、SpEL核心特性详解

1. 集合操作

列表/数组访问:

List<String> list = Arrays.asList("a","b","c");// 索引访问
exp = parser.parseExpression("[1]"); 
String elem = exp.getValue(list, String.class); // "b"// 集合投影(返回新集合)
exp = parser.parseExpression("![toUpperCase()]");
List<String> upper = exp.getValue(list, List.class); // ["A","B","C"]

Map访问:

Map<String, Integer> scores = Map.of("Tom", 90, "Jerry", 85);// Key访问
exp = parser.parseExpression("['Tom']");
Integer score = exp.getValue(scores, Integer.class); // 90

2. 方法调用

// 调用String方法
exp = parser.parseExpression("'abc'.substring(1, 2)");
String substr = exp.getValue(String.class); // "b"// 调用Bean方法
exp = parser.parseExpression("calculateDiscount(0.1)");
Double discount = exp.getValue(orderService, Double.class);

3. 运算符大全

类别运算符示例
算术+-*/%^2^3 → 8
关系<>==<=>=!=price > 100 ? 'high' : 'low'
逻辑andornotisVip and age > 18
正则matchesemail matches '[a-z]+@domain\\.com'
三元?:status ?: 'default'
Elvis?:name ?: 'Unknown'
Safe导航?.user?.address?.city

4. 类型操作

// 类型判断
exp = parser.parseExpression("'abc' instanceof T(String)");
Boolean isString = exp.getValue(Boolean.class); // true// 静态方法调用
exp = parser.parseExpression("T(java.lang.Math).random()");
Double random = exp.getValue(Double.class);// 构造函数
exp = parser.parseExpression("new com.example.User('Alice')");
User user = exp.getValue(User.class);
 

四、Spring集成实战

1. XML配置中的SpEL

<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"><property name="jdbcUrl" value="#{systemProperties['db.url'] ?: 'jdbc:mysql://localhost:3306/default'}"/><property name="maximumPoolSize" value="#{T(java.lang.Runtime).getRuntime().availableProcessors() * 2}"/>
</bean>

2. 注解配置中的SpEL

@Value("#{systemEnvironment['APP_HOME']}")
private String appHome;@Scheduled(fixedDelay = #{@configService.getInterval() * 1000})
public void scheduledTask() {// 定时任务
}@PreAuthorize("hasRole('ADMIN') or #user.id == authentication.principal.id")
public void updateUser(User user) {// 方法安全控制
}

3. Spring Data中的SpEL

// 查询方法中的SpEL
public interface UserRepository extends JpaRepository<User, Long> {@Query("SELECT u FROM User u WHERE u.status = :#{#status ?: 'ACTIVE'}")List<User> findByStatus(@Param("status") String status);
}// 实体中的默认值
@Entity
public class Article {@Id@GeneratedValueprivate Long id;@Columnprivate Date publishDate;@Transient@Value("#{T(java.time.LocalDate).now()}")private LocalDate currentDate;
}
 

五、高级技巧与最佳实践

1. 自定义函数扩展

public class StringUtils {public static String reverse(String input) {return new StringBuilder(input).reverse().toString();}
}// 注册自定义函数
StandardEvaluationContext context = new StandardEvaluationContext();
context.registerFunction("reverse", StringUtils.class.getDeclaredMethod("reverse", String.class));// 使用自定义函数
Expression exp = parser.parseExpression("#reverse('hello')");
String result = exp.getValue(context, String.class); // "olleh"

2. 模板表达式

ParserContext templateContext = new TemplateParserContext();// 解析模板
String template = "用户#{#user.name}的余额是#{#account.balance}";
Expression exp = parser.parseExpression(template, templateContext);// 设置上下文变量
context.setVariable("user", currentUser);
context.setVariable("account", userAccount);String message = exp.getValue(context, String.class);

3. 安全沙箱限制

// 创建安全上下文
SecurityManager securityManager = new SecurityManager();
securityManager.setRestrict(true);
securityManager.setAllowedTypes(Collections.singleton(String.class));StandardEvaluationContext context = new StandardEvaluationContext();
context.setSecurityManager(securityManager);// 尝试执行危险操作(将被阻止)
try {Expression exp = parser.parseExpression("T(java.lang.Runtime).getRuntime().exec('rm -rf /')");exp.getValue(context); // 抛出SecurityException
} catch (EvaluationException e) {System.err.println("危险操作被阻止!");
}
 

六、性能优化指南

1. 表达式编译

// 解析并编译表达式(提升10倍性能)
SpelCompiler compiler = SpelCompiler.getCompiler();
Expression compiledExp = compiler.compile(parser.parseExpression("amount * taxRate"));// 重复使用编译后的表达式
for (Order order : orders) {Double tax = compiledExp.getValue(order, Double.class);
}

2. 缓存策略

// 使用ConcurrentHashMap缓存编译后表达式
private static final Map<String, Expression> EXPR_CACHE = new ConcurrentHashMap<>();public Object evaluate(String exprStr, Object root) {Expression expr = EXPR_CACHE.computeIfAbsent(exprStr, key -> parser.parseExpression(key));return expr.getValue(root);
}

3. 避免性能陷阱

// 错误示例:每次解析新表达式
@Scheduled(fixedRate = 5000)
public void process() {Expression exp = parser.parseExpression(ruleEngine.getRule()); // 频繁解析exp.getValue(context);
}// 正确方案:预编译+缓存
private final Map<String, Expression> ruleCache = new ConcurrentHashMap<>();public void process() {Expression exp = ruleCache.computeIfAbsent(ruleEngine.getRule(), key -> parser.parseExpression(key));exp.getValue(context);
}
 

七、SpEL在Spring生态系统中的应用

1. Spring Security

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {// 方法级安全控制
}public interface BankService {@PreAuthorize("hasPermission(#accountId, 'ACCOUNT', 'WRITE')")void withdraw(Long accountId, BigDecimal amount);
}

2. Spring Integration

<int:router input-channel="input" expression="headers['type']"><int:mapping value="order" channel="orderChannel"/><int:mapping value="payment" channel="paymentChannel"/>
</int:router>

3. Spring Batch

<batch:job id="importJob"><batch:step id="processFile" next="#{jobParameters['skipStep'] ? 'skipStep' : 'nextStep'}"><!-- 步骤配置 --></batch:step>
</batch:job>
 

八、总结:SpEL最佳实践

  1. 适用场景

    • ✅ 动态配置值

    • ✅ 条件化Bean创建

    • ✅ 安全表达式

    • ✅ 简单业务规则

    • ❌ 复杂业务逻辑(应使用Java代码)

  2. 性能黄金法则

    安全建议

    • 永远不要执行不受信任的表达式

    • 生产环境启用SecurityManager

    • 限制可访问的类和包

终极提示:在Spring Boot中,可通过spring.expression.compiler.mode设置编译器模式(IMMEDIATE, MIXED, OFF)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87971.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87971.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/87971.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法导论第二十四章 深度学习前沿:从序列建模到创造式AI

第二十四章 深度学习前沿&#xff1a;从序列建模到创造式AI 算法的进化正在重新定义人工智能的边界 深度学习作为机器学习领域最活跃的分支&#xff0c;正以惊人的速度推动着人工智能的发展。本章将深入探讨五大前沿方向&#xff0c;通过原理分析、代码实现和应用场景展示&…

抽象工厂设计模式

1.问题背景&#xff1a; 现在有两个产品(Product)分别是手机壳(PhoneCase)和耳机(EarPhone)&#xff0c;但是他们会来自于各个生产厂商&#xff0c;比如说Apple和Android等等 那么至少会有四个产品&#xff0c;分别是安卓手机壳&#xff0c;安卓耳机&#xff0c;苹果手机壳&a…

GESP 3级 C++ 知识点总结

根据GESP考试大纲 (2024年3月版)&#xff0c;帮大家总结一下GESP 3级 C语言的知识点&#xff1a; 核心目标&#xff1a; 掌握C程序的基本结构&#xff0c;理解并能运用基础的编程概念解决稍复杂的问题&#xff0c;重点是函数、一维数组和字符串处理。 主要知识点模块&#x…

腾讯云主动型云蜜罐技术解析:云原生威胁狩猎的革新实践(基于腾讯云开发者社区技术网页与行业实践)

摘要 腾讯云主动型云蜜罐&#xff08;Active Cloud Honeypot&#xff09;通过动态诱捕机制和云原生架构&#xff0c;在威胁检测效率、攻击链还原深度、防御联动实时性等维度实现突破。相较于传统蜜罐&#xff0c;其核心优势体现在&#xff1a; 部署效率&#xff1a;分钟级完成…

企业微信wecom/jssdk的使用(入门)

概述 记录一个企业微信jssdk的使用&#xff0c;因为要用到图片上传、扫描二维码等工具。项目是uniapp开发的h5项目&#xff0c;fastadmin&#xff08;thinkphp5&#xff09;后端 先看官方文档 https://developer.work.weixin.qq.com/document/path/90547#%E5%BA%94%E7%94%A8…

大零售生态下开源链动2+1模式、AI智能名片与S2B2C商城小程序的协同创新研究

摘要&#xff1a;在流量红利消退、零售形态多元化的背景下&#xff0c;大零售生态成为商业发展的新趋势。本文聚焦开源链动21模式、AI智能名片与S2B2C商城小程序在零售领域的协同应用&#xff0c;探讨其如何打破传统零售边界&#xff0c;实现流量变现与用户资产化。研究表明&am…

Scrapy全流程(一)

创建一个scrapy项目:scrapy startproject mySpider 生成一个爬虫:scrapy genspider douban movie.douban.com 提取数据:完善spider&#xff0c;使用xpath等方法 保存数据:pipeline中保存数据 2 创建scrapy项目 下面以抓取豆瓣top250来学习scrapy的入门使用&#xff1a;豆瓣…

【Elasticsearch】TF-IDF 和 BM25相似性算法

在 Elasticsearch 中&#xff0c;TF-IDF 和 BM25 是两种常用的文本相似性评分算法&#xff0c;但它们的实现和应用场景有所不同。以下是对这两种算法的对比以及在 Elasticsearch 中的使用情况&#xff1a; TF-IDF - 定义与原理&#xff1a;TF-IDF 是一种经典的信息检索算法&am…

【QT】控件二(输入类控件、多元素控件、容器类控件与布局管理器)

文章目录 1.输入类控件1.1 LineEdit1.2 Text Edit1.3 Combo Box1.4 SpinBox1.5 Date Edit & Time Edit1.6 Dial1.7 Slider 2. 多元素控件2.1 List Widget2.2 Table Widget2.3 Tree Widget 3. 容器类控件3.1 Group Box3.2 Tab Widget 4. 布局管理器4.1 垂直布局4.2 水平布局…

【Docker基础】Docker镜像管理:docker pull详解

目录 1 Docker镜像基础概念 1.1 什么是Docker镜像&#xff1f; 1.2 镜像与容器的关系 1.3 镜像仓库(Registry) 2 docker pull命令详解 2.1 基本语法 2.2 参数解释 2.3 拉取镜像的基本流程 2.4 镜像分层结构解析 3 docker pull实战指南 3.1 基本使用示例 3.2 指定镜…

PixPin:一个强大且免费的截图贴图工具

PixPin 是一款国产免费的截图工具&#xff0c;支持屏幕截图、屏幕录制&#xff08;GIF&#xff09;、文字识别&#xff08;OCR&#xff09;以及贴图等功能。 高效截图 PixPin 支持自由选择或自动检测窗口&#xff0c;自定义截图区域&#xff0c;像素级精确捕捉&#xff0c;延时…

【测试报告】论坛系统

一、项目背景 1.1 测试目标及测试任务 测试目标旨在保障功能无漏洞、流程顺畅&#xff0c;实现多端显示交互一致&#xff0c;达成高并发场景下响应时间&#xff1c;2 秒等性能指标&#xff0c;抵御 SQL 注入等安全攻击&#xff0c;提升 UI 易用性与提示友好度&#xff1b; 背…

30天pytorch从入门到熟练(day1)

一、总体工作思路 本项目采用“从零构建”的策略&#xff0c;系统性地开展了深度学习模型的开发与优化工作。其目标在于通过全流程自研方式&#xff0c;深入理解模型构建、训练优化、推理部署的关键技术环节。整体路径分为以下核心阶段&#xff1a; 模型初步构建&#xff1a;以…

Subway Surfers Blast × 亚矩阵云手机:手游矩阵运营的终极变现方案

引爆全球&#xff1a;Subway Surfers Blast的流量红利​​ 随着Sybo Games最新力作《Subway Surfers Blast》全球上线&#xff0c;这款休闲消除游戏迅速席卷各大应用商店榜单。对于手游推广者而言&#xff0c;如何高效获取这波流量红利&#xff1f;​​亚矩阵云手机专业手游推…

mysql join的原理及过程

连接过程 每获得一条驱动表记录&#xff0c;就立即到被驱动表寻找匹配的记录。 对于两表连接来说&#xff0c;驱动表只会被访问一遍&#xff0c;但被驱动表却要被访问好多遍;具体访问几遍取决于对驱动表执行单表查询后的结果集中有多少条记录。 ​ 对于内连接来说&#xff0…

Hologres的EXPLAIN和EXPLAIN ANALYZE简介

文章目录 一、执行计划1、概念简介2、使用方式①、EXPLAIN②、EXPLAIN ANALYZE 二、算子解读1、SCAN2、Index Scan和 Index Seek3、Filter4、Decode5、Redistribution6、Join7、Broadcast8、Shard prune和Shards selected9、ExecuteExternalSQL10、Aggregate11、Sort12、Limit1…

49-Oracle init.ora-PFILE-SPFILE-启动参数转换实操

一早出现EMCC挂了&#xff0c;之后发现EMCC依赖的instance 挂了&#xff0c;重启startup后发现spfile无法启动。还是和小伙伴把基础问题搞清。spfile是动态文件、动态文件、动态文件&#xff0c;linux下vi看起来部分乱码部分是可编辑的&#xff0c;vi即使可以编辑也需要转换成p…

spring碎片

包的扫描过程 判断当前是否是文件夹获取文件夹里面的所有内容判断文件夹是否为空,为空的话直接返回如果文件夹不为空,则遍历文件夹里面的所有内容 遍历得到每个file对象,继续进行判断,如果还是文件,则进一步进行递归遍历得到的file对象不是文件夹,是文件得到包路径类名称-字符…

如何形成项目经验在多个项目间的高效复用?

要实现项目经验的跨项目高效复用&#xff0c;核心在于建立系统化总结机制、标准化知识表达、平台化共享工具。其中&#xff0c;标准化知识表达尤为关键&#xff0c;它通过统一模板和分类体系&#xff0c;确保不同项目的经验可以被快速理解、轻松匹配到新场景&#xff0c;从而提…

目标检测之YOLOV11谈谈OBB

引言&#xff1a;从轴对齐到定向边界框的范式转变 在计算机视觉领域&#xff0c;目标检测算法长期受限于轴对齐边界框&#xff08;AABB&#xff09;的固有缺陷——当面对航拍图像中的舰船、遥感影像中的建筑物或工业质检中的倾斜零件时&#xff0c;传统边界框会包含大量背景噪…