SpEL结合AOP示例

AOP不用多说,是spring框架的两大基石之一。SpEL是Spring Expression Language的缩写,意为Spring表达式语言,,其支持在运行时查询和操作对象图提供了更加丰富的功能,最特别的是方法调用与字符串模板功能。熟悉js的es6语法的小伙伴都知道,模板字符串,这个spel就类似js的模板字符串。

本次代码主要是熟悉使用语法,并布对应实际的应场景。

一、自定义注解

java 复制代码
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestAopAnn {

    /**
     * spEL
     * @return
     */
    String  spEL() default "";
}

二、自定义切面

java 复制代码
@Aspect
@Component
public class TestAopAspect {
    private final static Logger LOGGER = LoggerFactory.getLogger(TestAopAspect.class);
    
    @Pointcut("@annotation(org.example.boot3.aop.TestAopAnn)")
    public void pointCut(){}

    
    @AfterReturning(value = "pointCut()",returning = "result")
    public   void  doAfter(JoinPoint joinPoint,Object result){
        Method method = getMethod(joinPoint);
        TestAopAnn annotation = method.getAnnotation(TestAopAnn.class);
        if(annotation!=null){
            LOGGER.info("TestAopAspect-->doAfter-------后置织入");
          /// 通过spel表达式获取到形参的中name的值
            String value =getValue(joinPoint, method, annotation.spEL());
            LOGGER.info("TestAopAspect-->doBefore-------value={}",value);
             /// 将name追加到返回的list
            try {
                if(result!=null && result instanceof List){
                   List  list = (List) result;
                   list.add(value);
                }
     
            } catch (Exception e) {
                e.fillInStackTrace();
            }
        }
    }
    

    private   Method  getMethod(JoinPoint  joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        return methodSignature.getMethod();
    }

   /**解析spel*/
    private String  getValue(JoinPoint  joinPoint,  Method method,String elStr){
        StandardEvaluationContext context = new StandardEvaluationContext();
        DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
        /// 方法参数名称
        String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
        Assert.isTrue(parameterNames!=null,"参数列表不能为空");
        ///方法参数值
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < parameterNames.length; i++) {
            context.setVariable(parameterNames[i],args[i]);
        }
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(elStr);
        return (String) expression.getValue(context);
    }
}

三、测试接口

java 复制代码
public class TestReqVO {

    private String  name;

    private String  remark;
}
java 复制代码
@RestController
@RequestMapping("/api")
public class RestApi {
    /**
     * SpEL 调用对象方法
     * @param vo
     * @return
     */
    @GetMapping("/testSpEL1")
    @TestAopAnn(spEL = "#vo.getName()")
    public List<String> getSpELList1(TestReqVO vo){
        String[] arr = { "C" ,"C++","JAVA","GoLang","Rust","Python"};
        return new ArrayList<>(Arrays.stream(arr).toList());
    }

    /**
     * SpEL 调用对象属性
     * @param vo
     * @return
     */
    @GetMapping("/testSpEL2")
    @TestAopAnn(spEL = "#vo.name")
    public List<String> getSpELList2(TestReqVO vo){
        String[] arr = { "C" ,"C++","JAVA","GoLang","Rust","Python"};
        return  new ArrayList<>(Arrays.stream(arr).toList());
    }


    @GetMapping("/fluxList")
    public Flux<List<String>> getSpEL2(){
        String[] arr = { "C" ,"C++","JAVA","GoLang","Rust","Python"};
        ArrayList<String> list = new ArrayList<>(Arrays.asList(arr));
        return Flux.just(list);
    }
    
}

​​​​​​​

相关推荐
Thanks_ks10 小时前
SpringBoot 自动化部署实战:CI/CD 整合方案与避坑指南
pipeline·jenkins·springboot·自动化部署·gitlab ci/cd·ci/cd 实战·docker 容器化
豆芽脚脚2 天前
spel 多层list嵌套表达式踩坑记
windows·list·spel
无问8173 天前
Spring AOP:面向切面编程 详解代理模式
java·spring·代理模式·aop
保持学习ing4 天前
黑马Java面试笔记之框架篇(Spring、SpringMvc、Springboot)
java·笔记·spring·面试·mvc·mybatis·springboot
怡人蝶梦5 天前
Java大厂后端技术栈故障排查实战:Spring Boot、Redis、Kafka、JVM典型问题与解决方案
java·jvm·redis·elk·kafka·springboot·prometheus
怡人蝶梦6 天前
Java后端技术栈问题排查实战:Spring Boot启动慢、Redis缓存击穿与Kafka消费堆积
java·jvm·redis·kafka·springboot·prometheus
怡人蝶梦6 天前
Spring Boot启动慢?Redis缓存击穿?Kafka消费堆积?——Java后端常见问题排查实战
java·jvm·redis·kafka·springboot·prometheus·microservices
JAVA坚守者7 天前
Java 对接 Office 365 邮箱全攻略:OAuth2 认证 + JDK8 兼容 + Spring Boot 集成(2025 版)
springboot·oauth2·office365·java 开发·企业级开发·jdk8 兼容
黎黎黎明⁠⁢8 天前
SpringBoot整合Sa-Token:实现RBAC权限模型
java·sa-token·springboot·idea