找回密码
 会员注册
查看: 28|回复: 0

SpEL快速上手及实践

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
64074
发表于 2024-9-19 17:36:32 | 显示全部楼层 |阅读模式
简介SpEL常见用法快速入门实际应用SpEL内部实现的简单梳理总结简介SpringExpressionLanguage(简称SpEL,Sp:Spring,EL:ExpressionLanguage)是一个支持运行时查询和操作对象图的强大的表达式语言。在Spring产品组合中与我们常见的Beans模块、Core核心模块、Context上下文模块一起组成了Spring的核心容器,是表达式计算的基础,支持在运行时查询和操作对象,可以与基于XML和基于注解的Spring配置还有bean定义一起使用。Spring的体系结构SpEL常见用法SpEL的语法类似于JSP中EL表达式,使用#{…}作为定界符,所有在大框号中的字符都将被认为是SpEL。SpEL支持如下表达式:SpEL字面量:整数:#{8}小数:#{8.8}科学计数法:#{1e4}String:#{'string'}Boolean:#{true}SpEL引用bean,属性和方法:引用其他对象:#{car}引用其他对象的属性:#{car.brand}调用其它方法,还可以链式操作:#{car.toString()}调用静态方法静态属性:#{T(java.lang.Math).PI}SpEL支持的运算符号:算术运算符:+,-,*,/,%,^(加号还可以用作字符串连接)比较运算符:,==,>=, monitorConfigMap = apolloConfigService.getMonitorConfigMap();    if (MapUtils.isEmpty(monitorConfigMap) || !monitorConfigMap.containsKey(code)) {        return;    }    MonitorConfig monitorConfig = monitorConfigMap.get(code);    //当有返回值时需要校验一下结果是否符合预期    String resultType = monitorConfig.getResultType();    if (checkResult(result, resultType)) {        return;    }        //获取入参的SpEL表达式进行解析    String monitorSpEL = monitor.monitorSpEL();    String monitorTrace = String uuid = StringUtils.isNotBlank(monitorSpEL) ?             SpelParseUtil.generateKeyBySpEL(monitorSpEL, joinPoint) : StringUtils.EMPTY_STRING;    //截取一下异常信息    String otherParamsJson = "";    if (Objects.nonNull(ex)) {        Map otherParams = Maps.newHashMap();        String stackTraceAsString = Throwables.getStackTraceAsString(ex);        String errMsg = stackTraceAsString;        if (stackTraceAsString.length() > NumberConstant.NUMBER_512) {            errMsg = stackTraceAsString.substring(0,NumberConstant.NUMBER_512) + "...";        }        otherParams.put("异常信息", errMsg);        otherParamsJson = JsonUtil.silentObject2String(otherParams);    }    // 异步发送报警信息    asyncSendMonitor(scenes, monitorTrace, otherParamsJson);    }}......private static SpelExpressionParser parser = new SpelExpressionParser();private static DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();public static String generateKeyBySpEL(String spelString, JoinPoint joinPoint) {    // 通过joinPoint获取被注解方法    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();    Method method = methodSignature.getMethod();    // 使用spring的DefaultParameterNameDiscoverer获取方法形参名数组    String[] paramNames = nameDiscoverer.getParameterNames(method);    // 解析过后的Spring表达式对象    Expression expression = parser.parseExpression(spelString);    // spring的表达式上下文对象    EvaluationContext context = new StandardEvaluationContext();    // 通过joinPoint获取被注解方法的形参    Object[] args = joinPoint.getArgs();    // 给上下文赋值    for (int i = 0; i  bizOrderContext = BizOrderContext.create(OrderEventEnum.C1_CHANGE_JM_PRICE, request);    ZzAssert.isTrue(stateMachine.isCanFire(bizOrderContext), BizErrorCode.ORDER_STATUS_CHANGED);    stateMachine.fire(bizOrderContext);    return bizOrderContext.getResponse();}示例效果:SpEL内部实现的简单梳理SpEL在Spring内部的实现可以简单理解如下:语法分析首先用户调用ExpressionParser#parseExpression方法触发表达式解析。表达式解析器在内部先进行词法解析,将字符串形式的表达式拆分成不同的Token,如1+2表达式会被拆分成1、+、2三部分。解析时同时会参考上下文ParserContext,如上述示例中的#{name}表达式,解析器会先去掉前后缀#{},然后再进行解析。随后Token将被转换为抽象语法树,在内部使用SpelNode表示,为了简化用户操作语法树被包装到Expression。用户使用Expression#getValue方法获取表达式的值,在内部也会参考评估上下文EvaluationContext进行解析。总结本文只是简单的介绍了如何使用,实际场景中SpEL随处可见,除了上文中示例的监控报警之外,动态创建Documet类的Index、动态加解锁、接口缓存等都有非常多的实践。除此之外spring应用中常见的@cacheable、@Value,以及SpringSecurity框架中的@PreAuthorize、@PostAuthorize、@PreFilter、@PostFilter中都有SpEL的身影。参考资料[1]SpringExpressionLanguage(SpEL):https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions[2]SpEL你感兴趣的实现原理浅析:https://cloud.tencent.com/developer/article/1497676关于作者钱曙光,转转C2B业务研发工程师。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-26 11:13 , Processed in 1.778567 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表