过滤器(Filter)和拦截器(Interceptor)都是基于AOP特性来实现的请求处理操作。但对于两者的区别却很少有人能够分得清楚,下面我们就来看看二者的区别。
过滤器
以SpringBoot项目为例,要想使用过滤器首先需要实现Filter的接口,并且重写其中的doFilter()。
@Component
@WebFilter(urlPatterns = "/*")
public class TestFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(TestFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("执行init方法");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("过滤器方法");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
log.info("销毁!");
}
}
会看到在Filter接口中有三个方法
- void init(FilterConfig filterConfig):方法是在被初始化的时候进行调用,并且初始化操作在全局只会被调用一次,这个在打印的日志中可以看到。
- void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3):这个就是具体执行的过滤,通过这个方法来处理需要过滤的请求,并且,通过第三个参数FilterChain来调用下一个过滤器。
- void destroy():用于销毁过滤器的操作,在容器资源回收的时候调用。
实现拦截器
拦截器(Interceptor)
实现一个拦截器操作,需要去继承一个HandlerInterceptor接口,并且重写其中的preHandle()方法。
@Component
public class AuthHandlerInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(AuthHandlerInterceptor.class);
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取到请求头信息
String header = request.getHeader(tokenService.getHeader());
// 如果获取到请求头信息为空
if (header!=null){
String username = tokenService.getUsername(header);
log.info("获取到请求头信息 {}",username);
boolean verify = tokenService.verify(header, username);
if (verify){
return true;
}else {
throw new CertificationExpirationException("您的接口认证已过期!");
}
}else {
throw new AuthenticationFailedException("您无法访问此接口!");
}
}
}
在拦截器中也有三个需要实现的接口方法。
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):这个方法在请求之前被调用,例如上面我们实现的这种方式在调用之前需要验证用户请求是否包含TOKEN值。如果验证通过则继续调用,如果校验不通过,后面的业务就不会执行。
- void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView):在请求调用之后执行,但是会在DispatcherServlet 进行渲染之前被执行。
- void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex):在整个的请求结束之后执行,也就是在上面提到的DispatcherServlet渲染之后在执行。
创建好拦截器之后,就需要在配置文件中添加对应的拦截器配置。
@Configuration
public class AuthWebMvcConfig implements WebMvcConfigurer {
@Autowired
private AuthHandlerInterceptor authHandlerInterceptor;
/**
* 给除了 /login 的接口都配置拦截器,拦截转向到 authHandlerInterceptor
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authHandlerInterceptor)
// 拦截所有请求
.addPathPatterns("/**")
// 放行login请求
.excludePathPatterns("/login");
}
}
在了解了两者的机制之后,我们来看看二者的区别。
来源不同
过滤器是来自于Servlet 提供,而拦截器是Spring 框架提供的服务。
触发点不同
一个请求从浏览器发送到服务器的执行顺序如下。
- 第一步、进入到容器
- 第二步、进入到过滤器
- 第三步、进入到Servlet
- 第四步、进入到拦截器
- 第五步、执行控制器中的内容
按照上面的执行步骤,会看到由于执行的顺序不同,所以先会去执行过滤器中的内容,然后才会执行拦截器的内容。
实现不同
过滤器的实现是基于回调方法来实现,用到了责任链设计模式,所以当我们自定义实现过滤器的时候需要手动的调用下一个过滤器方法回调。
filterChain.doFilter(servletRequest,servletResponse);
否则后续的调用将无法进行。
拦截器是基于动态代理实现的,用到的是代理模式。最终操作过程如下图所示。
支持方式不同
上面提到过滤器是Servlet中的定义,所以要依赖于Servlet,只能在Web应用项目中使用,并且可以直接通过@WebFilter(urlPatterns = "/*")注入到容器中。而拦截器是由Spring容器中提供的组件,所以在所有的Spring使用场景中都可以使用。
使用场景不同
根据上面图中展示的调用顺序以及层次关系,可以知道,拦截器处理更接近于业务Controller层,所以主要用来做一些业务相关的判断,例如上面我们实现的登录鉴权判断。而过滤器通常是离业务层较远,所以只是来完成一些信息过滤操作。
总结
通过上面的分析,我们介绍了过滤器和拦截器的区别与联系,虽然都是基于AOP实现,但是在实际使用的时候还是要根据具体的使用场景来实现。
本文暂时没有评论,来添加一个吧(●'◡'●)