Spring中在Interceptor/Filter内获取请求对应方法并分析注解
嘿,在Spring里实现你要的这个需求完全不用自己造轮子,Spring本身就提供了现成的组件来搞定。我给你分两种场景讲,分别对应Interceptor和Filter的实现方式,优先推荐Interceptor的方案,更省心!
在Spring HandlerInterceptor中实现(首推)
因为Interceptor属于Spring MVC生命周期的一部分,当请求匹配到对应的@RequestMapping方法时,Spring会直接把目标方法封装成HandlerMethod传递给Interceptor的preHandle方法,你直接拿过来用就行,完全不用自己做路径匹配。
示例代码
首先写一个自定义Interceptor:
@Component public class AnnotationAnalysisInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 先判断当前handler是不是@RequestMapping方法对应的HandlerMethod if (handler instanceof HandlerMethod handlerMethod) { // 获取目标方法和Controller类 Method targetMethod = handlerMethod.getMethod(); Class<?> controllerClass = handlerMethod.getBeanType(); // 处理方法上的@RequireScore注解 RequireScore requireScore = targetMethod.getAnnotation(RequireScore.class); if (requireScore != null) { Score level = requireScore.level(); int score = requireScore.score(); // 这里可以写你的业务逻辑,比如校验用户分数是否达标 System.out.println("方法要求等级:" + level + ",分数:" + score); } // 处理Controller类上的@AnotherCustomAnnotation注解 AnotherCustomAnnotation classAnnotation = controllerClass.getAnnotation(AnotherCustomAnnotation.class); if (classAnnotation != null) { String value = classAnnotation.value(); System.out.println("Controller类注解值:" + value); } // 处理方法上的@AnotherCustomAnnotation注解 AnotherCustomAnnotation methodAnnotation = targetMethod.getAnnotation(AnotherCustomAnnotation.class); if (methodAnnotation != null) { String value = methodAnnotation.value(); System.out.println("方法注解值:" + value); } } // 返回true继续执行后续的请求流程,返回false则终止请求 return true; } }
注册Interceptor
在Spring Boot里,你可以通过WebMvcConfigurer来注册这个Interceptor:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private AnnotationAnalysisInterceptor annotationAnalysisInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(annotationAnalysisInterceptor) .addPathPatterns("/**"); // 指定要拦截的路径,这里是所有路径 } }
在Filter中实现(Servlet层面)
如果你的需求必须在Filter里处理(比如要在Spring MVC处理请求之前做一些操作),那可以借助Spring的RequestMappingHandlerMapping组件——它是Spring MVC内部存储所有@RequestMapping方法映射关系的核心Bean,我们可以用它来手动查找请求对应的方法。
示例代码
@Component public class AnnotationAnalysisFilter implements Filter { // 用@Lazy避免Filter初始化时Spring上下文还没加载好这个Bean @Lazy @Autowired private RequestMappingHandlerMapping requestMappingHandlerMapping; @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; try { // 查找当前请求对应的HandlerExecutionChain HandlerExecutionChain handlerChain = requestMappingHandlerMapping.getHandler(request); if (handlerChain != null) { Object handler = handlerChain.getHandler(); // 同样判断是不是HandlerMethod类型 if (handler instanceof HandlerMethod handlerMethod) { Method targetMethod = handlerMethod.getMethod(); Class<?> controllerClass = handlerMethod.getBeanType(); // 后面的逻辑和Interceptor完全一样,这里就不重复写了 RequireScore requireScore = targetMethod.getAnnotation(RequireScore.class); if (requireScore != null) { // 你的业务逻辑 } } } } catch (Exception e) { // 处理查找失败的情况,比如请求是静态资源或者没有匹配到任何@RequestMapping方法 e.printStackTrace(); } // 继续执行Filter链 chain.doFilter(servletRequest, servletResponse); } }
注意事项
- Filter是在Servlet层面执行的,比Spring MVC的Interceptor更早,所以用这种方式相当于提前做了一次路径匹配,性能上会比Interceptor稍差一点,因为Spring MVC后续还会再做一次匹配。
- 如果你的Controller被AOP代理了,
handlerMethod.getBeanType()可能返回代理类,这时候可以用handlerMethod.getMethod().getDeclaringClass()获取原始的Controller类,或者用AopUtils.getTargetClass(handlerMethod.getBean())获取目标对象的类。 - 如果你的自定义注解没有标注
@Inherited,那么子类继承父类Controller时,父类的注解不会被继承到子类,获取的时候要注意这一点。
内容的提问来源于stack exchange,提问作者payloc91
相关产品推荐
相关产品推荐

