共计 2093 个字符,预计需要花费 6 分钟才能阅读完成。
为什么需要统一处理请求参数?
在日常 Web 开发中,我们经常遇到这样的场景:

- 需要对接口参数进行非空校验、格式校验
- 记录请求参数的日志用于排查问题
- 对敏感参数进行脱敏处理
- 验证用户权限或签名
如果每个方法都重复这些代码,会导致大量冗余。更糟糕的是,当需要修改校验规则时,要改动所有相关方法。这时候,AOP 就能帮我们优雅地解决这个问题。
AOP vs 拦截器:如何选择?
Spring 提供了两种实现横切关注点的方案:
- 拦截器 (Interceptor)
- 基于 Servlet 过滤器链实现
- 适合处理 HTTP 层面的通用逻辑(如鉴权、日志)
-
只能获取到 HttpServletRequest 中的参数
-
AOP
- 基于动态代理实现
- 可以精确切入到具体方法
- 能获取方法入参、注解等元信息
- 适合业务层面的统一处理
当我们需要基于方法参数或注解做处理时,AOP 是更好的选择。
实战:实现参数处理切面
1. 基础切面定义
@Aspect
@Component
public class ParamAspect {
// 切入所有 Controller 方法
@Around("execution(* com.example.controller..*.*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取方法签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 获取请求参数
Object[] args = joinPoint.getArgs();
String[] paramNames = signature.getParameterNames();
// 参数预处理逻辑
processParams(method, paramNames, args);
// 执行原方法
return joinPoint.proceed(args);
}
}
2. 获取注解信息
private void processParams(Method method, String[] paramNames, Object[] args) {Annotation[][] paramAnnotations = method.getParameterAnnotations();
for (int i = 0; i < args.length; i++) {Object arg = args[i];
String paramName = paramNames[i];
// 检查 @RequestParam 注解
for (Annotation annotation : paramAnnotations[i]) {if (annotation instanceof RequestParam) {RequestParam requestParam = (RequestParam) annotation;
// 处理参数...
}
}
}
}
3. 添加校验逻辑
private void validateParam(String paramName, Object value) {if (value == null) {throw new IllegalArgumentException(paramName + "不能为空");
}
if (value instanceof String && ((String) value).trim().isEmpty()) {throw new IllegalArgumentException(paramName + "不能为空字符串");
}
// 更多校验规则...
}
性能优化建议
- 切面执行顺序
- 使用 @Order 注解控制切面顺序
-
将高频切面放在最后执行
-
减少切面数量
- 合并相似功能的切面
-
避免在切面中执行耗时操作
-
缓存反射结果
- Method 对象等元信息可以缓存
- 避免每次请求都解析方法签名
private static final Map<Method, MethodMeta> methodCache = new ConcurrentHashMap<>();
private MethodMeta getMethodMeta(Method method) {
return methodCache.computeIfAbsent(method, m -> {
// 解析并缓存方法元数据
return new MethodMeta(m);
});
}
生产环境注意事项
- 与 Spring Security 整合时,注意切面执行顺序要在认证之后
- 敏感参数处理要放在切面最前面
- 考虑添加 @ConditionalOnProperty 控制切面开关
- 分布式场景下,需要确保切面逻辑幂等
扩展思考
- 参数自动解密
- 可以自定义注解如 @DecryptParam
-
在切面中识别该注解并对参数解密
-
微服务参数传递
- 通过 Feign 拦截器统一添加参数
-
使用 Spring Cloud Sleuth 传递上下文
-
动态切面
- 基于配置中心动态调整切面逻辑
- 实现热更新的参数处理规则
总结
通过 Spring AOP 实现参数统一处理,不仅能让代码更整洁,还能提高开发效率。关键是找到业务中的通用关注点,用切面优雅地解决。希望本文能帮助你掌握这一实用技巧!
正文完
发表至: 未分类
近两天内
