SpringBoot自定义注解支持EL表达式

SpringBootAOP + SpringEL表达式 实现动态传参(基于MethodBasedEvaluationContext)

SPEL表达式

Spring 提供的EL表达式解析特性强化了注解能力。能做到注解中的属性值动态地从方法参数中获取,而不是简单地设置固定值。

AOP依赖

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.17.RELEASE</version>
</dependency>

自定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface LogAnn {
// 操作人
String operator() default "";

// 业务单号
String bizNo() default "";

// 操作
BusinessAction action() default BusinessAction.OTHER;
}

操作字段的枚举类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public enum BusinessAction {
/**
* 其它
*/
OTHER,

/**
* 新增
*/
INSERT,

/**
* 修改
*/
UPDATE,

/**
* 删除
*/
DELETE,

/**
* 授权
*/
GRANT,

/**
* 导出
*/
EXPORT,

/**
* 导入
*/
IMPORT,

/**
* 强退
*/
FORCE,

/**
* 生成代码
*/
GENCODE,

/**
* 清空数据
*/
CLEAN,
}

注解的使用方式

其中LogTestModel用于测试,类中包含userName和orderId字段。

1
2
3
4
5
6
@PostMapping("LogAnn")
@LogAnn(operator = "#logTestModel.userName", bizNo = "#logTestModel.orderId", action = BusinessAction.OTHER)
public String LogAnn(@RequestBody LogTestModel logTestModel) {
System.out.println("测试");
return "success";
}

Aspect代码

拦截LogAnn注解作为切点

使用MethodBasedEvaluationContext进行SPEL解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Slf4j
@Aspect
@Component
public class LogAspect {
/**
* 用于获取方法参数定义名字.
*/
private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
/**
* 用于SpEL表达式解析.
*/
private static final SpelExpressionParser parser = new SpelExpressionParser();

@Pointcut("@annotation(com.hong.demo.common.annotate3.LogAnn)")
public void LogAnn() {
}

@Around("LogAnn()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取目标类
Object target = joinPoint.getThis();
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
// 获取方法
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
// 获取参数
Object[] args = joinPoint.getArgs();
// 可解决代理对象问题
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
LogAnn logAnn = method.getAnnotation(LogAnn.class);
MethodBasedEvaluationContext context = new MethodBasedEvaluationContext(target, targetMethod, args, parameterNameDiscoverer);
// 处理注解上的值
String bizNo = logAnn.bizNo();
String bizNoValue = getExpValue(context, bizNo);
log.info("bizNo:{}", bizNoValue);
String operator = logAnn.operator();
String operatorValue = getExpValue(context, operator);
log.info("operator:{}", operatorValue);
// to do
return joinPoint.proceed();
}

private String getExpValue(MethodBasedEvaluationContext context, String expr) {
Expression expression = this.parser.parseExpression(expr);
return (String) expression.getValue(context);
}
}

测试结果

image-20231209124414983

image-20231209124458721

以上就是在AOP中使用SPEL进行动态参数的demo,最后不要忘记在配置中打开“@EnableAspectJAutoProxy”。


SpringBoot自定义注解支持EL表达式
http://example.com/2025/11/29/SpringBoot自定义注解支持EL表达式/
作者
TuBoShu
发布于
2025年11月29日
许可协议