Spring 常用的三种拦截器详解

2026-02-18 19:38:23

前言

在开发过程中,我们常常使用到拦截器来处理一些逻辑。最常用的三种拦截器分别是 AOP、 Interceptor 、 Filter,但其实很多人并不知道什么时候用AOP,什么时候用Interceptor,什么时候用Filter,也不知道其拦截顺序,内部原理。今天我们详细介绍一下这三种拦截器。

拦截器顺序

我们现在有一个controller接口,叫做test,现在我们在项目有定义了三个拦截器,其顺序如下

Filter(before) > Interceptor(before) > AOP(before) > test方法 > AOP(after) > Interceptor(after) > Filter(after)

具体流程如下两幅图片。

所以有时候我们使用不了AOP/Interceptor, 只能使用Filter。

比如我们现在是一个Get请求,但是别人却发送了一个Post请求,这时候只有Filter才能拦截,只能使用Filter.

又比如我们在Interceptor获取了请求参数以后,因为是一个流,后面controller就会获取不到,我们一般会采用包装类来实现重复读取。但假如我们直接使用AOP就完全可以避免这个问题了。

类似的例子比较多,所以我们应该知其然,也要知其所以然。下面我们介绍一下三种拦截器的具体用法。

Filter拦截器

filter是servlet层面的提供拦截器,和spring无关。只是说现在spring/springboot一统江湖,很多项目在spring的基础上面使用filter。那我们如果在spring项目中使用filter拦截器呢

@Slf4j

public class FirstFilter implements Filter {

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

log.info("FirstFilter before doFilter");

filterChain.doFilter(servletRequest, servletResponse);

}

}

@Slf4j

public class SecondFilter implements Filter {

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

log.info("SecondFilter before doFilter");

filterChain.doFilter(servletRequest, servletResponse);

}

}

@Slf4j

@Configuration

public class FilterConfig {

@Bean

public FilterRegistrationBean firstFilter() {

FilterRegistrationBean registration = new FilterRegistrationBean();

registration.setFilter(new FirstFilter());

registration.addUrlPatterns("/*");

registration.setName("FirstFilter");

// 数字越小,优先级越高

registration.setOrder(1);

return registration;

}

@Bean

public FilterRegistrationBean secondFilter() {

FilterRegistrationBean registration = new FilterRegistrationBean();

registration.setFilter(new SecondFilter());

registration.addUrlPatterns("/*");

registration.setName("SecondFilter");

// 数字越大,优先级越低

registration.setOrder(2);

return registration;

}

}

输出结果

FirstFilter before doFilter

SecondFilter before doFilter

Interceptor拦截器

Interceptor是springmvc给我们提供的拦截器,只有在sotingmvc中才可以使用

@Slf4j

@Component

public class FirstInterceptor implements HandlerInterceptor {

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

log.info("FirstInterceptor preHandle");

return true;

}

}

@Slf4j

@Component

public class SecondInterceptor implements HandlerInterceptor {

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

log.info("SecondInterceptor preHandle");

return true;

}

}

@Configuration

public class InterceptorConfig implements WebMvcConfigurer {

@Autowired

private FirstInterceptor firstInterceptor;

@Autowired

private SecondInterceptor secondInterceptor;

// 配置拦截规则

public void addInterceptors(InterceptorRegistry registry) {

// 按照注册的顺序,依次执行

registry.addInterceptor(firstInterceptor)

.addPathPatterns("/**")

.excludePathPatterns("/task/**");

registry.addInterceptor(secondInterceptor)

.addPathPatterns("/**")

.excludePathPatterns("/spring/**");

}

}

输出结果

FirstInterceptor preHandle

SecondInterceptor preHandle

AOP拦截器

AOP是我们非常常用的拦截器,织入点,有before,after,around等,我们今天以around为例

@Aspect

@Component

public class LoggerAOP {

@Pointcut("execution (public * com.xxx.controller..*(..))")

public void pointcutLogger() {}

@Around("pointcutLogger()")

public Object methodAround(ProceedingJoinPoint joinPoint) throws Throwable {

try {

logger.info("request className = {}, method = {}, ip = {}, param = {}", className, methodName, ip, param);

resp = joinPoint.proceed();

long duration = stopwatch.elapsed(TimeUnit.MILLISECONDS);

logger.info("response className = {}, method = {}, resp = {}, cost = {}ms", className, methodName, buildResp(resp), duration);

}

catch (Throwable e) {

logger.error("logger request className = {}, method = {} fail message = {} ",

className, methodName, e.getMessage(), e);

throw e;

}

return resp;

}

}

最后

我们介绍了一下spring中,常用的三种拦截器,以及他们在springboot中如何使用。

最后给大家出一个小作业,如果把上面三个拦截器放到一个项目中,他会输出什么顺序呢?

[INFO 2024-07-27 16:01:52.146] [http-nio-8099-exec-2] [] - [FirstFilter.doFilter:17] [FirstFilter before doFilter]

[INFO 2024-07-27 16:01:52.146] [http-nio-8099-exec-2] [] - [SecondFilter.doFilter:17] [SecondFilter before doFilter]

[INFO 2024-07-27 16:01:52.148] [http-nio-8099-exec-2] [] - [FirstInterceptor.preHandle:18] [FirstInterceptor preHandle]

[INFO 2024-07-27 16:01:52.148] [http-nio-8099-exec-2] [] - [SecondInterceptor.preHandle:18] [SecondInterceptor preHandle]

[INFO 2024-07-27 16:01:52.148] [http-nio-8099-exec-2] [cdc644d0-afdf-4283-bf52-fc5fdd217746] - [LoggerAOP.methodAround:52] [request className = TestController, method = testController, ip = 0:0:0:0:0:0:0:1, param = [null]]

[INFO 2024-07-27 16:01:52.149] [http-nio-8099-exec-2] [cdc644d0-afdf-4283-bf52-fc5fdd217746] - [TestController.testController:57] [main process]

[INFO 2024-07-27 16:01:52.149] [http-nio-8099-exec-2] [cdc644d0-afdf-4283-bf52-fc5fdd217746] - [LoggerAOP.methodAround:62] [response className = TestController, method = testController, resp = "ok", cost = 0ms]