SpringBoot中的过滤器、拦截器的区别

The difference between filter and interceptor in SpringBoot

Posted by alovn on April 13, 2019

前言

从概念上来讲,filter是servlet规范定义的,而interceptor是spring定义的。 最简单明了的区别就是过滤器可以修改request,而拦截器不能。

过滤器 Filter

过滤器Filter,是Servlet提供的功能。可通过过滤器,对请求进行拦截,它可以对几乎所有请求进行过滤,一个过滤器实例只能在容器初始化时调用一次。

字面意思:过滤器就是过滤的作用,在web开发中过滤一些我们指定的url, 那么它能帮我们过滤什么呢? 那功能可就多了:比如过拦截掉我们不需要的接口请求,修改请求(request)和响应(response)内容,完成CORS跨域请求等,可以实现安全校验(过滤掉一下低俗的文字、危险字符等),还可以根据session判断用户是否登录、判断访问的请求URL是否有访问权限等。主要还是可对请求进行预处理。

使用过滤器的目的,是用来做一些过滤操作,获取我们想要获取的数据,比如在web开发中,对传入的request、response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者Controller进行业务逻辑操作。

接下来介绍下,在springboot如何实现过滤器功能。

@WebFilter时Servlet3.0新增的注解,原先实现过滤器,需要在web.xml中进行配置,而现在通过此注解,启动启动时会自动扫描自动注册。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@WebFilter(urlPatterns = "/login/*",filterName = "loginFilter")
public class MyLoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("filter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filter doing...");
    }

    @Override
    public void destroy() {
        System.out.println("filter destroy");
    }
}

然后在启动类加入@ServletComponentScan注解即可。

1
2
3
4
5
6
7
8
@SpringBootApplication
@ServletComponentScan
public class GiftpkgServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(GiftpkgServiceApplication.class, args);
    }
}

程序启动后根据输出日志,可以看到过滤器已经生效了,init方法只会在启动的时候执行一次。如果要注册多个过滤器的话,原本是可以使用web.xml配置指定执行顺序,使用@WebFilter注解时,可以通过@Order注解指定执行顺序,值越小越先执行。 若没有使用@Order指定顺序的话,默认是通过过滤器的名字排序的,比如 AuthFilter 就会比 LogFilter先执行,因为首写字母A在L前面。

拦截器 Interceptor

Spring 的拦截器 HandlerInterceptor 的功能跟过滤器类似,但是提供更精细的的控制能力:在request被响应之前、request被响应之后、视图渲染之前以及request全部结束之后。我们不能通过拦截器修改request内容,但是可以通过抛出异常(或者返回false)来暂停request的执行。 拦截器只能对Controller中的请求进行拦截,对一些静态资源的请求就没办法处理了。 配置拦截器也很简单,Spring 为此提供了基础类WebMvcConfigurerAdapter ,我们只需要重写addInterceptors 方法添加注册拦截器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class SecurityInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
       if(session.getAttribute("sso")!=null){
            return true;
        }
        response.sendRedirect("/login");
        return false;
        //return super.preHandle(request, response, handler);
    }
}

@Configuration
public class WebSecurityConfig extends WebMvcConfigurationSupport // implements WebMvcConfigurer
         {
    @Bean
    public SecurityInterceptor getSecurityInterceptor() {
        return new SecurityInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //多个拦截器时,执行顺序和添加顺序相同
        InterceptorRegistration addInterceptor = registry.addInterceptor(getSecurityInterceptor());
        // 排除配置
        addInterceptor.excludePathPatterns("/error");
        addInterceptor.excludePathPatterns("/login**");

        // 拦截配置
        addInterceptor.addPathPatterns("/**");
    }
}

两者区别

过滤器和拦截器非常相似,但是它们有很大的区别。

1
2
3
4
最简单明了的区别就是过滤器可以修改request,而拦截器不能。
过滤器需要在servlet容器中实现,拦截器可以适用于javaEE,javaSE等各种环境。
拦截器可以调用IOC容器中的各种依赖,而过滤器不能。
过滤器只能在请求的前后使用,而拦截器可以详细到每个方法。

总的来说,过滤器就是筛选出你要的东西,比如requeset中你要的那部分。 拦截器在做请求控制的比较多,比如终止一些流程。

在整个请求的过程,一图胜千言。过滤器与拦截器的执行顺序: springboot-filter-interceptor

另外从其它博客看到到两者的不同之处:

  1. 拦截器是基于动态代理的,而过滤器是基于函数回调。
  2. 拦截器不依赖于servlet容器,通过动态代理实现,过滤器依赖于servlet容器。
  3. 拦截器可以在方法前后,异常前后等调用,而过滤器只能在请求前和请求后各调用一次。
  4. 拦截器可以利用依赖注入,因此在Spring框架程序中,优先拦截器。