动态获取方法注解是权限校验拦截器的关键起点,需在运行时通过反射读取@Retention(RetentionPolicy.RUNTIME)声明的注解,结合Spring AOP或反射API定位Method对象,调用getAnnotation()获取实例,并解析value()、requireAll()等属性,再关联当前用户权限完成判定,不通过则抛出AccessDeniedException。

动态获取方法上的注解是实现权限校验拦截器的关键起点。它不依赖编译期硬编码,而是在运行时通过反射精准提取开发者在方法上声明的权限要求,为后续比对用户权限提供依据。
用反射准确读取方法级注解
注解必须声明为 @Retention(RetentionPolicy.RUNTIME),否则运行时不可见。获取时需先定位到目标 Method 对象:
- 在 Spring AOP 的
@Around切面中,用joinPoint.getSignature()转为MethodSignature,再调用getMethod() - 若在普通工具类或非代理场景下,需通过类对象和方法名获取:
clazz.getDeclaredMethod("methodName", paramTypes) - 注意:
getDeclaredMethod才能拿到 private 或 package-private 方法;getMethod仅返回 public 方法(含父类) - 调用
method.getAnnotation(YourPermissionAnnotation.class)获取注解实例,返回 null 表示未标注
处理注解属性与权限表达逻辑
注解通常定义多个可配置项,如权限码列表、匹配策略等,反射读取后需结构化解析:
-
value()常设为String[],表示所需权限标识(如{"USER_READ", "USER_EDIT"}) -
requireAll()控制校验逻辑:true 表示全满足,false 表示任一满足即可 - 避免直接比较字符串,建议统一转小写、trim 空格,并使用
Set存储用户权限,提升contains或containsAll效率 - 权限标识推荐用枚举或配置中心管理,防止散落各处的字符串字面量导致维护困难
结合上下文完成权限判定
仅读到注解还不够,必须关联当前执行主体的权限数据才能做判断:
- Spring Security 环境下,从
SecurityContextHolder.getContext().getAuthentication().getAuthorities()提取GrantedAuthority列表 - 若基于 JWT,需从 token payload 中解析出
roles或permissions字段 - 将注解值(如
String[])转为标准权限集合,再按requireAll策略比对用户权限集合 - 不通过时抛出
AccessDeniedException,由全局异常处理器统一响应 403;通过则调用proceed()放行
注意反射使用的边界与兼容性
生产环境对反射有隐性约束,需提前规避风险:
-
private方法需配合setAccessible(true),但部分安全策略(如 SecurityManager 或 JVM 参数-Djdk.reflect.allowNonPublicAccess=false)会禁用该操作 - 参数类型严格匹配:
int.class和Integer.class是不同签名,定义注解时建议统一用包装类声明参数类型 - CGLIB 代理下,目标方法可能被隐藏,应优先使用
joinPoint.getTarget().getClass()而非代理类来反射查找 - 频繁反射调用有性能开销,可考虑缓存已解析的注解元数据(如用
ConcurrentHashMap)










