spring|spring web|拦截器、过滤器、aop排序问题
基于spring-boot 4.0.x
Filter 多个过滤器排序
1. 使用 `@Order(int)` 注解:数值越小,优先级越高,doFilter 前置越早执行
2. 代码注册方式(`FilterRegistrationBean`):bean 内部的`setOrder()`,优先级高于注解
3. 老 web.xml 配置:按 xml 中定义顺序执行(SpringBoot 基本不用)
Interceptor 多个拦截器排序
WebMvcConfigurer#addInterceptors 添加顺序决定
先 add 的 Interceptor,preHandle 优先执行
AOP 多个切面(Aspect)排序
切面类上加 `@Order(int)`:数值越小,切面优先级越高
汇总如下:
| 组件 | 排序标识 | 排序规则 | 后置通知顺序 |
|---|---|---|---|
| Filter | @Order / FilterRegistrationBean.setOrder() | 数字越小,前置越早执行 | 逆序执行 |
| Interceptor | addInterceptors 注册顺序 | 先注册,preHandle 越早执行 | postHandle、afterCompletion 逆序 |
| AOP 切面 | 切面类上 @Order | 数字越小,切面越优先切入 | 切面通知逆序执行 |
源码
https://gitee.com/jysemel-spring/spring-boot/tree/master/action/action-web-sample/action-web-sample-filter-order
pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<!-- AOP 切面依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aspectj</artifactId>
</dependency>
</dependencies>
部分代码
过滤器
package com.jysemel.spring.boot.filter;
import jakarta.servlet.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.io.IOException;
import static org.aspectj.weaver.tools.cache.SimpleCacheFactory.path;
@Slf4j
@Component
@Order(0)
public class Custom0Filter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 彻底跳过静态图标请求
if(path.contains("favicon.ico")){
// 直接返回,不进入 SpringMVC、拦截器、异常处理
return;
}
log.info("【1-Custom0Filter】请求前置拦截");
chain.doFilter(request, response);
log.info("【1-Custom0Filter】请求后置收尾");
}
}
拦截器
package com.jysemel.spring.boot.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Slf4j
public class Custom0Interceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("【2-Custom0Interceptor】preHandle 接口前置校验");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
log.info("【2-Custom0Interceptor】postHandle 接口后置处理");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
log.info("【2-Custom0Interceptor】afterCompletion 请求最终收尾");
}
}
aop
package com.jysemel.spring.boot.aop;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@Slf4j
@RestControllerAdvice
@Order(0)
public class Custom0ResponseAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
log.info("【4-Custom0ResponseAdvice】统一处理接口返回体");
return body;
}
}
执行结果
2026-09-17T22:02:57.515+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.spring.boot.filter.Custom0Filter : 【1-Custom0Filter】请求前置拦截
2026-09-17T22:02:57.515+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.spring.boot.filter.Custom1Filter : 【1-Custom1Filter】请求前置拦截
2026-09-17T22:02:57.527+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.s.b.interceptor.Custom0Interceptor : 【2-Custom0Interceptor】preHandle 接口前置校验
2026-09-17T22:02:57.527+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.s.b.interceptor.Custom1Interceptor : 【2-Custom1Interceptor】preHandle 接口前置校验
【业务代码】Controller业务逻辑执行
2026-09-17T22:02:57.535+08:00 INFO 40508 --- [nio-8080-exec-1] com.jysemel.spring.boot.aop.CustomAop : 【3-AOP】Controller方法执行成功
2026-09-17T22:02:57.544+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.s.boot.aop.Custom0ResponseAdvice : 【4-Custom0ResponseAdvice】统一处理接口返回体
2026-09-17T22:02:57.544+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.s.boot.aop.Custom1ResponseAdvice : 【4-Custom1ResponseAdvice】统一处理接口返回体
2026-09-17T22:02:57.549+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.s.b.interceptor.Custom1Interceptor : 【2-Custom1Interceptor】postHandle 接口后置处理
2026-09-17T22:02:57.550+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.s.b.interceptor.Custom0Interceptor : 【2-Custom0Interceptor】postHandle 接口后置处理
2026-09-17T22:02:57.550+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.s.b.interceptor.Custom1Interceptor : 【2-Custom1Interceptor】afterCompletion 请求最终收尾
2026-09-17T22:02:57.550+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.s.b.interceptor.Custom0Interceptor : 【2-Custom0Interceptor】afterCompletion 请求最终收尾
2026-09-17T22:02:57.550+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.spring.boot.filter.Custom1Filter : 【1-Custom1Filter】请求后置收尾
2026-09-17T22:02:57.550+08:00 INFO 40508 --- [nio-8080-exec-1] c.j.spring.boot.filter.Custom0Filter : 【1-Custom0Filter】请求后置收尾
