如何在Spring Boot中使用Aspect仅记录请求体而非所有参数?
解决Spring AOP无法精准匹配@RequestBody参数的问题
我明白你遇到的困扰了——你的Aspect当前没有精准捕获到@RequestBody标记的请求体参数,反而记录了所有传入的参数。这是因为args(.., @RequestBody requestBody)的写法在参数匹配上存在歧义,Spring AOP无法准确识别出仅带有该注解的参数,尤其是当方法包含多个参数时更容易出错。
下面给你两种可靠的解决方案,推荐第二种,适配性更强:
方案一:优化切入点表达式(适用于参数位置固定的场景)
如果你的控制器方法中@RequestBody参数的位置固定(比如是唯一参数或最后一个参数),可以修改切入点的args表达式,精准绑定目标参数:
// 当@RequestBody是方法唯一参数时 @Before("logRequestMapping() && executeController() && args(@RequestBody requestBody)") public void logRequestBody(JoinPoint joinPoint, Object requestBody) { LOGGER = LoggerFactory.getLogger(joinPoint.getTarget().getClass()); if (requestBody != null) { LOGGER.info("Method : {}, Request Body:{}", LOGGER.getName() + "." + joinPoint.getSignature().getName(), MaskingUtil.jsonifyAndMask(requestBody)); } }
这种写法的局限性在于,如果@RequestBody参数在参数列表中间,或者方法存在多个参数,匹配逻辑就会失效。
方案二:手动识别@RequestBody参数(通用解决方案)
这种方法通过遍历方法参数和对应的注解,精准定位带有@RequestBody的参数,同时可以直接判断参数是否为null,决定是否输出日志,适配所有参数位置的情况:
import org.springframework.web.bind.annotation.RequestBody; import java.lang.reflect.Method; import org.aspectj.lang.reflect.MethodSignature; // 省略其他必要导入 @Before("logRequestMapping() && executeController()") public void logRequestBody(JoinPoint joinPoint) { // 获取方法签名与反射对象 MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method targetMethod = methodSignature.getMethod(); // 获取参数注解数组与参数值数组 Annotation[][] paramAnnotations = targetMethod.getParameterAnnotations(); Object[] paramValues = joinPoint.getArgs(); // 获取目标类的Logger实例 LOGGER = LoggerFactory.getLogger(joinPoint.getTarget().getClass()); // 遍历参数,查找带有@RequestBody注解的参数 for (int i = 0; i < paramAnnotations.length; i++) { for (Annotation annotation : paramAnnotations[i]) { if (annotation instanceof RequestBody) { Object requestBody = paramValues[i]; // 仅当请求体不为null时输出日志 if (requestBody != null) { LOGGER.info("Method : {}, Request Body:{}", LOGGER.getName() + "." + methodSignature.getName(), MaskingUtil.jsonifyAndMask(requestBody)); } // 通常一个方法仅一个@RequestBody,找到后直接退出循环 return; } } } }
这个方案的优势:
- 不受参数位置限制,无论
@RequestBody在参数列表的哪个位置都能精准捕获 - 直接判断请求体是否为null,避免空值日志输出
- 逻辑清晰,避免切入点表达式的匹配歧义
另外,建议把LOGGER的初始化移到类级别(如果不需要目标类的Logger的话):
private static final Logger LOGGER = LoggerFactory.getLogger(YourAspectClassName.class);
如果确实需要使用目标控制器类的Logger,当前在方法内获取的方式是可行的。
内容的提问来源于stack exchange,提问作者Atul Agrawal
相关产品推荐
相关产品推荐

