如何获取处理当前请求的端点方法引用(非当前方法)
问题描述
我有如下控制器类:
@RestController public class Controller { @GetMapping("endpoint") public void endpoint() { } }
我需要获取处理当前请求的方法引用(即Controller#endpoint()),注意并非在当前方法内部获取,而是处于过滤器或服务类这类场景中。最终目标是在自定义Spring Security栈里判断目标方法上是否存在@SomeRelevantAnnotation,不过这部分超出本次问题范围。
我目前想到的方案是:通过RequestContextHolder获取请求实例,再借助HandlerMapping#getHandler(request)获取方法引用,想问有没有更简便的实现方式?
回答
你的思路其实已经非常贴合Spring的请求处理逻辑了,不过确实有更简洁的方式可以快速拿到目标方法引用,下面给你两种方案参考:
方案一:基于RequestAttributes直接获取(初始思路优化)
Spring在处理请求时,会把匹配到的HandlerMethod存入请求属性中,你可以直接从RequestContextHolder里获取,不需要手动调用HandlerMapping的方法:
// 获取当前请求上下文 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes != null) { HttpServletRequest request = attributes.getRequest(); // 从请求属性中直接取出匹配的HandlerMethod Object handler = request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE); if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Method targetMethod = handlerMethod.getMethod(); // 这里targetMethod就是你要的Controller#endpoint()方法引用 } }
这个方式避免了手动查找处理器的步骤,直接复用Spring已经处理好的结果。
方案二:注入RequestMappingHandlerMapping直接获取(更简洁)
如果你的组件(比如过滤器、服务类)可以依赖注入,直接注入RequestMappingHandlerMapping,它提供了直接获取HandlerMethod的方法,一步到位:
@Autowired private RequestMappingHandlerMapping requestMappingHandlerMapping; public void getTargetHandlerMethod() { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes == null) { // 没有请求上下文,做异常处理或返回 return; } HttpServletRequest request = attributes.getRequest(); try { HandlerMethod handlerMethod = requestMappingHandlerMapping.getHandlerMethod(request); Method targetMethod = handlerMethod.getMethod(); // 成功拿到目标方法引用 } catch (NoHandlerFoundException e) { // 处理请求没有匹配到任何控制器方法的情况 e.printStackTrace(); } }
这个方式最简洁,因为RequestMappingHandlerMapping已经封装了所有请求匹配的逻辑,直接调用它的getHandlerMethod就能拿到最终的HandlerMethod实例,后续你可以通过handlerMethod.getMethod()拿到方法引用,进而判断方法上的注解。
注意事项
- 一定要确保在请求上下文存在的场景下调用这些方法,否则
RequestContextHolder.getRequestAttributes()会返回null,建议先做非空判断。 - 如果是在Spring Security的过滤器中,你也可以通过
FilterInvocation对象直接获取HttpServletRequest,再套用上面的方案。
内容的提问来源于stack exchange,提问作者Emanuel George Hategan

