【Spring EL<一>✈️ 】SL 表达式的应用

目录

🍸前言

🍻一、Spring EL

       1.1 定义

        1.2 常见使用方式

🍺二、项目案例

        2.1 实现一个简单的案例

        2.2 创建注解

        2.3 切面类实现

        2.4 创建测试接口

        2.5 测试

🍹三、章末


🍸前言

        小伙伴们大家好,前段时间在网上无意间听到了一个很耳生的名词 “Spring EL 表达式”,这几天通过文章、视频的方式了解了些,然后再本地实操下

🍻一、Spring EL

       1.1 定义

         首先来看下全称 Spring Expression Language ,正如命名所言,是 Spring 框架中一种表达式语言。类似于其他编程语言中的表达式语言,用于在运行时计算值或执行特定任务,比如在运行时评估复杂的表达式,通过这些表达式可以访问和操作应用程序上下文中的对象

        1.2 常见使用方式

        其实在项目中这种语法应该挺常见的比如下面这些:

        (1)通过 EL 表达式获取 bean 属性

"#{beanName.property}"

        (2)通过 EL 表达式调用某个 bean 方法

"#{bean.myMethod(args)}"

        (3)通过 EL 表达式进行运算

"#{num1 + num2}"

        ...

        使用方式有很多,本地就挑最常用以及最常见的使用方式,结合注解使用,动态的处理注解参数

🍺二、项目案例

        2.1 实现一个简单的案例

        比如自定义一个注解,用于控制方法级别的日志记录,但日志级别是根据运行时条件动态决定的,通过 Spring EL 表达式实现如下

        注:本地环境需要一个可以启动的 SpringBoot 项目,并且引入了 aop 依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
            2.2 创建注解

        创建一个注解,声明作用域为运行时,并且是作用于方法上面的,另外声明了一个方法,默认值为 true,也就是默认打印日志

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author HuangBen 
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecution {
    String condition() default "true"; // 默认总是记录日志
}

        2.3 切面类实现

       实现了在目标方法执行时环绕通知,动态的获取方法上的注解值,解析比对,判断是否需要打印日志

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author HuangBen 
 */
@Aspect
@Component
public class LoggingAspect {

    private final SpelExpressionParser parser = new SpelExpressionParser();
    private final DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

    @Around("@annotation(logExecution)")
    public Object logAround(ProceedingJoinPoint joinPoint, LogExecution logExecution) throws Throwable {
        boolean shouldLog = evaluateCondition(joinPoint, logExecution.condition());
        
        if (shouldLog) {
            System.out.println("Executing: " + joinPoint.getSignature().getName() + ", Log Level determined by SpEL.");
        }

        try {
            Object result = joinPoint.proceed();
            //到这里,目标方法执行完毕,要返回的内容先暂存,执行 finally 方法体
            return result;
        } finally {
            if (shouldLog) {
                System.out.println("Completed: " + joinPoint.getSignature().getName());
            }
        }
    }

    //用于解析 SpringEL 表达式并获取解析结果
    private boolean evaluateCondition(ProceedingJoinPoint joinPoint, String expression) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        MethodBasedEvaluationContext context = new MethodBasedEvaluationContext(
                null,
                method,
                joinPoint.getArgs(),
                parameterNameDiscoverer
        );
        Expression exp = parser.parseExpression(expression);
        return exp.getValue(context, Boolean.class);
    }
}

        2.4 创建测试接口

        这里就简单的写个接口,通过传入的参数决定是否打印日志

        注:这里的 "#input.equalsIgnoreCase('important')" 就是一个简单的表达式,input 表示提供的变量值,后面的是字符串方法,会忽略大小比较字符串是否等于目标值

@GetMapping("/springel")
    @LogExecution(condition = "#input.equalsIgnoreCase('important')")
    public void performAction(String input) {
        System.out.println("Performing action with input: " + input);
        // 实际业务逻辑...
    }

       

        如果单纯的比较输入的参数,这里也可以在切面类中实现,但是如果每个接口的 SpringEl 比较的内容都不一样的,阁下又该如何应对, if else 大军吗,不如直接换一个表达式,每个接口都可以有自己的 SpringEL 表达式(这样,编码的可用性不就增强了),比如可以判断输入的字符的长度是否大于 5,来决定是否打印日志,结果如下,注解正常工作

        2.5 测试

        2.5.1 输入参数为打印日志:

        2.4.2 输入参数为不需要打印

        2.5 总结

         这个案例只是简单演示了注解中的 SpringEL 表达式使用方式,通过在目标方法上加上注解,在注解里面写好自定义的 SpringEL 表达式,然后在切面类里面通过 SpringEL 解析工具处理表达式,获取结果即可

🍹三、章末

        文章初步的了解了 SpringEL 表达式的使用方式,以及结合具体的案例了解 Spring AOP 注解的常见用法

        文章到这里就结束了~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

先锋 Coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值