Spring Boot 自定义注解结合 Spel 表达式实现动态解析
在实际开发中,经常需要根据方法参数动态生成某些值,比如日志记录、参数校验、缓存 key 生成等。SpEL(Spring Expression Language)强大的表达式能力可以帮我们轻松实现这些需求。本文将介绍如何通过自定义注解结合 SpEL 实现动态解析。
一、需求分析
目标:
- 通过自定义注解,动态解析方法参数值。
- 支持 SpEL 表达式,例如:#param.name 获取对象属性值。
- 如果不是 SpEL 表达式,直接取值。
二、实现步骤
- 创建自定义注解
java
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SpelValue {
/**
* SpEL 表达式或参数字段名称
*/
String value();
}
- @Target:指定注解使用的位置为方法。
- @Retention:运行时保留,便于在 AOP 中动态获取。
- @Documented:生成文档时包含注解信息。
- 自定义切面
切面需要拦截方法,并根据注解定义的 SpEL 表达式进行解析和处理。
java
@Slf4j
@Aspect
@Component
public class SpelValueAspect {
@Around("@annotation(spelValue)")
public Object aroundSpel(ProceedingJoinPoint joinPoint, SpelValue spelValue) throws Throwable {
String value = spelValue.value();
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
String className = joinPoint.getTarget().getClass().getName();
String methodName = method.getName();
if (StringUtils.isEmpty(value)) {
value = className + ":" + methodName;
}
String key = SpelExpressionUtils.parserSpel(method, joinPoint.getArgs(), value, String.class, className + ":" + methodName);
log.info("获取到注解上value的解析出来的值为 {}",key);
return joinPoint.proceed();
}
}
3. 测试
定义一个服务类
java
public interface ITestService {
void test(RenderBO renderBO);
void test(String text);
void test(String text,String input);
void test(String text,String input,String output);
}
@Service
public class TestService implements ITestService{
@SpelValue("#renderBO.textKey + ' ' + 'cm'")
@Override
public void test(RenderBO renderBO) {
return;
}
@Override
@SpelValue("#text")
public void test(String text) {
}
@SpelValue("not spel")
@Override
public void test(String text, String input) {
}
@SpelValue
@Override
public void test(String text, String input, String output) {
}
}
执行之后输出如下:
text
2025-01-16 17:16:36.435 INFO 25080 --- [ main] c.s.b.annotation.spel.SpelValueAspect : 获取到注解上value的解析出来的值为 key cm
2025-01-16 17:16:36.439 INFO 25080 --- [ main] c.s.b.annotation.spel.SpelValueAspect : 获取到注解上value的解析出来的值为 xxxxxx
2025-01-16 17:16:36.440 INFO 25080 --- [ main] c.s.b.annotation.spel.SpelValueAspect : 获取到注解上value的解析出来的值为 not spel
2025-01-16 17:16:36.441 INFO 25080 --- [ main] c.s.b.annotation.spel.SpelValueAspect : 获取到注解上value的解析出来的值为 com.ssn.boot.service.TestService:test
总结
通过以上方式,我们实现了一个支持 SpEL 动态解析的自定义注解。这种方式能够大大增强代码的灵活性,适合用于日志记录、动态缓存键生成、方法调用监控等场景。希望本文对你有所帮助!