要通过反射获取方法参数上的注解并实现自定义参数解析器,关键是运行时识别被特定注解标记的参数并据此注入或转换数据;需确保注解声明@Retention(RUNTIME),遍历getParameterAnnotations()二维数组定位目标注解,结合上下文(如Spring的HandlerMethodArgumentResolver)解析真实值,并缓存解析结果以提升性能。

要通过反射获取方法参数上的注解并实现自定义参数解析器,关键不是“直接拿到参数值”,而是在运行时识别出哪些参数被特定注解标记,并据此注入或转换对应的数据。这常见于 Spring MVC 的 @RequestBody、@PathVariable 或自定义如 @CurrentUserId 等场景。
一、确保注解支持运行时读取
自定义注解必须声明 @Retention(RetentionPolicy.RUNTIME),否则反射无法获取:
- 缺少该元注解 →
method.getParameterAnnotations()可能返回空数组或 null - 同时建议用
@Target(ElementType.PARAMETER)明确限定作用位置,避免误用 - 示例:
```java
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUser {
String value() default "";
}```
二、定位带注解的参数并提取元数据
不能只靠 Method.getParameters() 获取参数名(Java 8+ 需编译加 -parameters),重点是遍历每个参数的注解数组:
- 调用
method.getParameterAnnotations(),返回二维数组:每行对应一个参数的注解列表 - 对每个参数,用
annotatedElement.isAnnotationPresent(YourAnno.class)快速判断是否存在目标注解 - 若存在,用
annotatedElement.getAnnotation(YourAnno.class)获取实例,再调用.value()等方法读属性 - 注意:
getParameterAnnotations()返回的是Annotation[][],索引需与参数顺序严格对应
三、结合上下文完成参数解析逻辑
仅读到注解还不够,解析器需知道“此时该给这个参数塞什么值”。典型做法是:
- 在 Spring MVC 中,实现
HandlerMethodArgumentResolver接口,重写supportsParameter()和resolveArgument() -
supportsParameter()判断是否为本解析器负责的参数(比如检查是否有@CurrentUser) -
resolveArgument()中从当前请求上下文(如HttpServletRequest、SecurityContext或 ThreadLocal)取出真实值,返回给 Controller 方法 - 非 Spring 环境可手动遍历 Method + 参数类型 + 注解组合,用反射
setAccessible(true)赋值(慎用于生产)
四、注意反射性能与缓存策略
每次请求都反射解析开销大,应避免重复扫描:
- 将已确认支持的参数位置(如第2个参数带
@CurrentUser)缓存为Map - Spring 内部已对
HandlerMethod做了参数解析结果缓存,自定义解析器也建议做类似封装 - 若注解属性固定(如无表达式),可提前解析并缓存注解实例,而非每次调用
getAnnotation()










