【框架篇】过滤器和拦截器的区别以及使用场景

在项目开发中,常常会同时配置拦截器(Interceptor)和过滤器(Filter),以下就是它们两个主要的区别:

过滤器(Filter)

配置和实现

Filter的实现还是很简单的,可以实现对应的Filter接口,也可以通过@WebFilter注解对Url进行拦截,其中主要是有三个方法:

  • init():在容器启动初始化锅炉其的时候被调用,在过滤器的整个生命周期之内进会被调用一次,如果执行失败,过滤器就不会生效
  • doFilter():在容器的每一次请求都会触发这个方法,通过FilterChain来调用下一个过滤器
  • destroy():当容器销毁过滤器的实例的时候调用,一般用于销毁或关闭资源,在整个生命周期中也是只会被调用一次
    @Component
    public class MyFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("Filter 前置");
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("Filter 处理中");
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        @Override
        public void destroy() {
            System.out.println("Filter 后置");
        }
    }

拦截器(Interceptor) 

配置和实现

拦截器是链式调用的,一个应用中可以存在多个拦截器,一个请求可以触发的多个拦截器,并且每一个拦截器按照声明的顺序依次执行。主要是通过实现HandlerInterceptor接口,其中主要是有三个方法:

  • preHandler():在请求之前调用。如果返回false,当前请求结束,后续也不会执行
  • postHandler():只有preHandler返回true才会执行,在Controller中的方法调用之后、DispatcherServlet返回渲染视图之前被调用
  • afterCompletion():只有preHandle()方法返回值为true时才会执行,在整个请求结束之后、DispatcherServlet渲染了对应的视图之后执行
    @Component
    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("Interceptor 前置");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("Interceptor 处理中");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("Interceptor 后置");
        }
    }

过滤器和拦截器区别

过滤器和拦截器的主要区别有以下几点:

  • 底层实现不同:
    • 过滤器:底层通过函数回调来实现。在自定义过滤器中实现的doFilter()方法有一个FilterChain参数,它是一个回调接口。
    • 拦截器:Java的反射机制(动态代理)。
  • 使用范围
    • 过滤器:依赖Tomcat等容器,仅用于web程序。
    • 拦截器:由Spring容器管理,可用于多种程序。
  • 触发时机(重点):
    • 过滤器:在请求进入到容器后,进入servlet之前进行预处理,请求结束是在servlet处理完以后。
    • 拦截器:拦截器是在servlet之后,进入到Controller之前进行预处理,在Controller中渲染了对应的视图之后请求结束。

  • 注入Bean的的情况不同:
    • 过滤器:在过滤器中注入service是可行的。
    • 拦截器:在拦截器中注入service是不可行的,原因是拦截器的加载是在spring容器初始化之前的,如果如果注入会出现错误。解决方案就是手动注入如下
      @Configuration
      public class MyMvcConfig implements WebMvcConfigurer {
          //让 Spring 容器能够通过这个方法来获取MyInterceptor实例
          @Bean
          public MyInterceptor getMyInterceptor(){
              System.out.println("注入了MyInterceptor");
              return new MyInterceptor();
          }
          
          @Override
          public void addInterceptors(InterceptorRegistry registry) {
              registry.addInterceptor(getMyInterceptor()).addPathPatterns("/**");
          }
      }

      使用registry.addInterceptor(getMyInterceptor()).addPathPatterns("/**");来注册拦截器。这里不是直接使用new MyInterceptor(),而是调用getMyInterceptor方法获取实例。这样做的好处是,在获取MyInterceptor实例时,由于getMyInterceptor方法是由 Spring 容器管理的(因为它在@Configuration类中),Spring 会确保在创建MyInterceptor实例时,相关的依赖(如可能需要注入的 Service)已经被正确初始化。

使用场景

一般在项目中,这两个是配合在一起来进行使用的,比如我在项目中实现用户上下文的打通,首先通过过滤器拦截请求,将用户的唯一id存入到请求的body当中,再通过拦截器,从body中获取openid存入到封装的用户上下文对象当中。

//在网关集成过滤器
@Component
@Slf4j
public class LoginFilter implements GlobalFilter {

    @Override
    @SneakyThrows
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpRequest.Builder mutate = request.mutate();
        String url = request.getURI().getPath();
        log.info("LoginFilter.filter.url:{}", url);
        if (url.equals("/user/doLogin")) {
            return chain.filter(exchange);
        }
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        log.info("LoginFilter.filter.url:{}", new Gson().toJson(tokenInfo));
        String loginId = (String) tokenInfo.getLoginId();
        mutate.header("loginId", loginId);
        return chain.filter(exchange.mutate().request(mutate.build()).build());
    }

}
public class LoginIntercepter implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String loginId = request.getHeader("loginId");
        LoginContextHolder.set("loginId",loginId);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        LoginContextHolder.remove();
    }
}

<think>好的,我现在需要回答用户关于过滤器拦截器区别及其在Web开发中的应用的问题。首先,我应该回顾一下已有的知识,并查看用户提供的引用内容,确保回答准确。 用户提到了四个引用,其中引用2、3、4涉及过滤器拦截器区别。根据这些引用,过滤器拦截器区别主要在实现方式、作用范围、使用场景等方面。比如,拦截器更灵活,能在请求前后执行,而过滤器主要用于URL编码、参数过滤安全校验。另外,Spring中的拦截器位于org.springframework.web.filter包,而过滤器javax.servlet.Filter的实现。 接下来,我需要组织这些信息,分点说明两者的区别。首先,定义过滤器拦截器的基本概念,然后从实现层面、作用范围、功能特点、依赖框架等方面进行比较。同时,要结合引用中的内容,比如过滤器在Spring中的位置,拦截器更灵活等。 在应用场景部分,需要分别列出过滤器拦截器的典型用途,比如过滤器的URL编码、安全校验,拦截器的日志记录、权限检查等。还要注意区分它们的使用框架过滤器是Servlet规范,拦截器属于Spring MVC。 然后,生成相关问题,可能需要围绕它们的区别、具体实现、选择时机等方面提问。比如如何选择两者,或者它们的执行顺序问题。 需要确保回答结构清晰,使用中文,正确应用LaTeX格式,比如提到的类名用$Filter$$HandlerInterceptor$。同时,引用标识要自然地加在相关段落末尾,如引用[^2]、[^3]等。 最后检查是否符合用户的要求,特别是系统级指令中的格式要求,比如行内数学表达式是否正确使用$...$,独立公式是否用$$...$$,但在这个问题中可能较少涉及数学公式,但如果有类名或代码,可能需要用代码块或斜体表示。 总结下来,回答的结构应该是:定义过滤器拦截器,分点对比区别,列举应用场景,最后生成相关问题。需要确保引用正确,信息准确,语言通顺。</think>### 过滤器拦截器区别及其应用 #### 1. **基本定义** - **过滤器(Filter)** 过滤器Java Servlet规范的一部分,基于回调机制实现,作用于Web容器层面。它主要用于对请求响应进行预处理或后处理,例如编码转换、安全校验等。 示例代码结构: ```java public class MyFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { // 预处理逻辑 chain.doFilter(request, response); // 传递给下一个过滤器或Servlet // 后处理逻辑 } } ``` - **拦截器(Interceptor)** 拦截器是Spring MVC框架提供的功能,基于反射机制实现,作用于控制器(Controller)层面。它可以在请求处理前、处理后或视图渲染后执行逻辑,例如日志记录、权限验证等。 示例代码结构: ```java public class MyInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 请求处理前逻辑 return true; // 是否继续执行 } public void postHandle(...) { /* 处理后逻辑 */ } } ``` #### 2. **核心区别** | **对比维度** | **过滤器(Filter)** | **拦截器(Interceptor)** | |--------------------|----------------------------------------------|-----------------------------------------------| | **实现方式** | 基于Servlet规范(`javax.servlet.Filter`)[^4] | 基于Spring MVC框架(`HandlerInterceptor`) | | **作用范围** | 所有Web请求(如静态资源) | 仅Spring管理的控制器请求 | | **执行顺序** | 在拦截器之前执行 | 在过滤器之后执行 | | **依赖框架** | 不依赖Spring,属于Web容器功能 | 依赖Spring MVC | | **功能灵活性** | 功能较单一,适合基础处理 | 更灵活,支持细粒度控制(如依赖注入) | #### 3. **应用场景** - **过滤器的典型用途** - **编码转换**:统一设置请求/响应的字符集(如UTF-8)。 - **安全校验**:过滤非法参数或敏感词汇。 - **日志记录**:记录请求耗时、IP等信息(但更推荐用拦截器实现)。 - **拦截器的典型用途** - **权限验证**:在`preHandle`中检查用户登录状态或角色。 - **性能监控**:统计接口响应时间。 - **数据预处理**:向请求中添加公共参数(如用户ID)。 #### 4. **如何选择?** - **优先使用过滤器**:若需处理所有Web资源(如静态文件)或与Servlet容器紧密相关的逻辑(如`HttpServletRequest`包装)。 - **优先使用拦截器**:若需访问Spring上下文(如依赖注入)或需要精细控制Controller前后的逻辑。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lose_rose777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值