想在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" -- 三元表达式