zoukankan      html  css  js  c++  java
  • 过滤器和拦截器有啥区别,这次会了!

    这个是不久前在面试的时候遇到的一个问题,当时直接懵了,两个单拎出来,虽然不太完全,但都大概知道可以对请求进行拦截,放在一起比较,可真是头疼。

    其实之前面试完就去学习了一波,只不过那个时候没及时总结,现在总结一下,以免日后遇到这类问题又给忘咯。

    要理解这类问题,光靠死记硬背可能当时有用,过一阵子就差不多忘了。要想真的牢记,我们必须要实操一下。

    Filter的使用

    首先,要使用Filter,必须实现javax.servlet.Filter接口:

    public interface Filter {
    	//web应用加载进容器,Filter对象创建之后,执行init方法初始化,用于加载资源,只执行一次。	
        public default void init(FilterConfig filterConfig) throws ServletException {}
    	//每次请求或响应被拦截时执行,可执行多次。
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException;
    	//web应用移除容器,服务器被正常关闭,则执行destroy方法,用于释放资源,只执行一次。
        public default void destroy() {}
    }
    
    • init和destroy是default方法,实现类可以不用实现。
    • doFilter必须实现,也就是说,作为一个过滤器,doFilter必须要定义。
    • doFlilter方法中传进来的FilterChain对象用来调用下一个过滤器。

    拦截器的使用

    public interface HandlerInterceptor {
    	//拦截handler的执行 --> 在HanlerMapping决定适合的handler之后,[在HandlerAdater调用handler之前执行。]
    	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		return true;
    	}
    	//拦截handler的执行 --> [在HandlerAdapter调用handler之后],在DispatcherServlet渲染视图之前执行
    	default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    			@Nullable ModelAndView modelAndView) throws Exception {
    	}
    	//视图渲染后调用,且只有preHandle结果为true,才会调用
    	default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
    			@Nullable Exception ex) throws Exception {
    	}
    }
    
    //DispatcherServlet
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return; //遍历所有的interceptors,调用preHandle方法,只有返回true,才能进行下去
    }
    
    // 这里也就是处理Contrller
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
    //视图渲染
    applyDefaultViewName(processedRequest, mv);
    //视图渲染之后调用
    mappedHandler.applyPostHandle(processedRequest, response, mv);
    

    过滤器与拦截器到底有啥区别呢?

    一、实现原理不同

    • 过滤器的实现基于回调函数
    • 拦截器基于Java的反射机制【动态代理】实现。

    二、使用范围不同

    • 过滤器是Servlet的规范,需要实现javax.servlet.Filter接口,Filter使用需要依赖于Tomcat等容器。
    • 拦截器是Spring组件,定义在org.springframework.web.servlet包下,由Spring容器管理【又有更加丰富的生缪那个周期处理方法,细粒度,且能够使用Spring中的资源】,不依赖Tomcat等容器。

    三、触发时机不同

    这一段在HandlerInterceptor类的注释上可以发现,两者的触发时机是不同的:

    • 过滤器:对请求在进入后Servlet之前或之后进行处理。
    • 拦截器:对请求在handler【Controller】前后进行处理。

    四、执行顺序不同

    同时配置了过滤器和拦截器的情形:

    MyFilter1 前
    MyFilter2 前
    MyInterceptor1 在Controller前执行
    MyInterceptor2 在Controller前执行
    controller方法执行...
    MyInterceptor2 Controller之后,视图渲染之前
    MyInterceptor1 Controller之后,视图渲染之前
    MyInterceptor2 视图渲染完成之后执行
    MyInterceptor1 视图渲染完成之后执行
    MyFilter2 后
    MyFilter1 后
    
    • 过滤器的顺序

    每一次都将chain对象传入,达到最后接口回调的效果:

    • 拦截器的顺序

    preHandle1 -> preHande2 -> 【Controller】 -> postHandle2 -> postHandle1 -> afterCompletion2 -> afterComplention1 preHandle按照注册顺序,后两个与注册顺序相反。

    • 一个拦截器的preHandle为false,则之后的所有拦截器都不会执行。
    • 一个拦截器的preHandle为true,则这个拦截器的triggerAfterCompletion一定会执行。
    • 只有所有的拦截器preHandler都为true,也就是正常执行,postHandle才会执行。
    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = 0; i < interceptors.length; i++) {
                HandlerInterceptor interceptor = interceptors[i];
                //一旦当前拦截器preHandle的返回值为false,那么从上一个可用的拦截器的afterCompletion开始
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false; //这里返回false意为 后续不进行下去了。
                }
                this.interceptorIndex = i;//interceptorIndex初始化为-1,只有当前拦截器preHandle为true,才会赋值当前的i。
            }
        }
        return true;
    }
    
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
        throws Exception {
    
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = interceptors.length - 1; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }
    }
    
    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
        throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
            for (int i = this.interceptorIndex; i >= 0; i--) 
    }
    

    五、控制执行顺序方式不同

    两者默认都是使用注册顺序,如果想要认为控制执行的顺序,方式略有不同:

    • 过滤器
      • 如果想要强制改变,可以使用@Order注解。
    • 拦截器
      • 如果使用order()方法
    @Order(2)
    @Component
    public class MyFilter1 implements Filter {}
    
    @Component
    public class WebAdapter implements WebMvcConfigurer {
    
        @Autowired
        MyInterceptor1 myInterceptor1;
    
        @Autowired
        MyInterceptor2 myInterceptor2;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(myInterceptor1).addPathPatterns("/**").order(2);
            registry.addInterceptor(myInterceptor2).addPathPatterns("/**").order(1);
        }
    }
    

    总结

    • 原理实现上:过滤器基于回调实现,而拦截器基于动态代理。

    • 控制粒度上:过滤器和拦截器都能够实现对请求的拦截功能,但是在拦截的粒度上有较大的差异,拦截器对访问控制的粒度更细。

    • 使用场景上:拦截器往往用于权限检查、日志记录等,过滤器主要用于过滤请求中无效参数,安全校验。

    • 依赖容器上:过滤器依赖于Servlet容器,局限于web,而拦截器依赖于Spring框架,能够使用Spring框架的资源,不仅限于web。

    • 触发时机上:过滤器在Servlet前后执行,拦截器在handler前后执行,现在大多数web应用基于Spring,拦截器更细。

    参考链接:

  • 相关阅读:
    Hdu 5396 Expression (区间Dp)
    Lightoj 1174
    codeforces 570 D. Tree Requests (dfs)
    codeforces 570 E. Pig and Palindromes (DP)
    Hdu 5385 The path
    Hdu 5384 Danganronpa (AC自动机模板)
    Hdu 5372 Segment Game (树状数组)
    Hdu 5379 Mahjong tree (dfs + 组合数)
    Hdu 5371 Hotaru's problem (manacher+枚举)
    Face The Right Way---hdu3276(开关问题)
  • 原文地址:https://www.cnblogs.com/summerday152/p/13658788.html
Copyright © 2011-2022 走看看