SpringBoot SpEL支持方法参数解析

想在IDEA中支持方法提示, 需要下载SpEL Assistant插件, 用法在这里

这里仅说AOP时支持方法参数

DemoAop.java:

java 复制代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DemoAop {
    /**
     * 支持SpEL表达式
     */
    String value();
}

MyXXXAspect.java:

java 复制代码
@EnableAspectJAutoProxy
@Aspect
@Slf4j
public class CustomMetadataAspect implements BeanFactoryAware {

    private final ExpressionParser parser = new SpelExpressionParser();
    private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
    @Setter
    private BeanFactory beanFactory;

    @Before("@annotation(demoAop)")
    public void atBefore(JoinPoint joinPoint, DemoAop demoAop) {
		String result = demoAop.value();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method targetMethod = signature.getMethod();
        Object[] args = joinPoint.getArgs();
        // noinspection DataFlowIssue
        MethodBasedEvaluationContext context =
            new MethodBasedEvaluationContext(null, targetMethod, args, pnd);
        context.setBeanResolver(new BeanFactoryResolver(beanFactory));
        // 可添加额外加参数, 如after切点添加result返回值: context.setVariable("额外参数", 参数值);
        result = parser.parseExpression(result).getValue(context, String.class);
        log.info("result is: {}", result);
    }

其实需要的代码行数特别少, 不需要花里胡哨的写法;

另外我一般会写上rootObject(MethodBasedEvaluationContext的第一个参数), 方便调用一些内容, 比如SpringSecurity中的@PreAuthorize中的hasRole()/hasAnyRole()/hasPermission()等等方法, 都是通过rootObject来实现的

示例我的一个RootObject:

java 复制代码
@Data
@AllArgsConstructor
@SuppressWarnings({"unused"})
public class RobinMetadataRootObject {
    private final Method method;

    private final Object[] args;

    private final Object target;

    private final Class<?> targetClass;

    public String getMethodName() {
        return this.method.getName();
    }
}
java 复制代码
// 解析时
public void atBefore(JoinPoint joinPoint, DemoAop demoAop) {
    ...
    // 初始化
    RobinMetadataRootObject rootObject = new RobinMetadataRootObject(targetMethod, extractArgs(targetMethod, args),
            joinPoint.getTarget(), joinPoint.getTarget().getClass());
    // 赋值
    MethodBasedEvaluationContext context =
            new MethodBasedEvaluationContext(rootObject, targetMethod, args, parameterNameDiscoverer);
    ...
}

可以方便的取方法和函数名称

Spring中的一些其他rootObject, 可供参考

Cache: CacheExpressionRootObject

Security: SecurityExpressionRoot

一些常见SpEL用法, 这里仅做示例, rootObject以, 不做详细解释:

java 复制代码
public String test(String id, Integer[] idList) {
    return id;
}
  • "#id" -- 直接取值
  • "1 > 2 && 3 == 4 && 5 > 6"关系运算符, 支持> / < / >= / <= / !=, 其中null小于任何值
  • 运算符支持纯字母等效替代: lt ('<')、gt ('>')、le ('<=')、ge ('>=')、eq ('==')、ne ('!= ')、div ('/')、mod ('%')、not ('!') 不区分大小写
  • "#id.startsWith('a')" -- 调用一些方法
  • "#id?.startsWith('b')" -- 空安全
  • "getMethodName() + getMethod() + getArgs()[0] + #args[0]" -- root上的字段/方法
  • "#p0+#a0" -- 以p或a前缀 + 参数序号来取值
  • "@taskExecutor.activeCount" -- 使用@符号 + bean名称调用其他bean
  • "1 + 2 - 3 * 4 / 5 - -6 % 7" -- 加减乘除, 正负数, 取余
  • "'abc' + true + null + 123" -- 各种字面量
  • "{1, 2, 3, 4, 5}.?[ #this > 3 ]" -- 内联列表以及过滤(返回值为4,5)
  • "{1, 2, 3, 4, 5}.^[ #this > 1 ]" -- 查找第一个符合条件的值(结果为2)
  • "{1, 2, 3, 4, 5}.&[ #this > 1 ]" -- 查找最后一个符合条件的值(结果为5)
  • "#username ?: 'abcd'" -- 默认值 如果username为 null, 则赋值为"abcd"
  • "new String(234)" -- 创建对象
  • "true ? 1 : 2" -- 三元表达式
相关推荐
SL_staff6 分钟前
打破风控迭代死循环:用决策编排重构业务与技术协作链路
java·产品·全栈
Mikko737 分钟前
Redis 连接数满了服务端有错误信息吗?连接数不增加却命令超时?6.2 实测连接池、超时与大 key 怎么判定
java·spring boot·redis·后端
.Bryce.43 分钟前
从零到一开发技术名词大全:从需求分析到 AI Agent 工程
java·网络·人工智能·agent·需求分析·agent评测
SL_staff1 小时前
JVS-APS的7个刚性约束设计:从无限产能幻觉到可执行排产的工程实践
java·spring cloud·全栈
代码山河2 小时前
基本类型转换:自动类型转换与强制类型转换
java·学习·架构·教程·面向对象·项目
Escalating_xu4 小时前
【Linux 网络编程】五种 I/O 模型与非阻塞 I/O:从“等数据”到正确处理 EAGAIN
java·linux·网络
程序猿乐锅4 小时前
万字详解Single-flight(单飞模式)
java·开发语言·分布式·后端·学习·single-flight
Java后端的Ai之路4 小时前
【AIAgent开发】-Agent工具封装成CLI(纯干货!!!)
java·javascript·人工智能·agent·cli
AntsData5 小时前
用 12K+ 条亚马逊评论信号,定位机械键盘下一版该改什么
java·大数据·计算机外设
code2cat5 小时前
【随笔】连续批处理:长短请求怎样在迭代之间补位
java·人工智能·后端·大语言模型·vllm