首页 > 编程知识 正文

Interceptor和Filter 哪个先执行?

时间:2023-11-21 14:50:17 阅读:289176 作者:SGWM

Interceptor和Filter都是在web应用程序中进行过滤和处理请求和响应的机制。在web应用程序处理请求的过程中,请求会经过一系列的过滤器和拦截器,在这个过程中我们需要分清楚他们的顺序才能做到有效地处理请求和响应。本文将从多个角度对Interceptor和Filter 哪个先执行进行详细的阐述。

一、执行环境的不同

Interceptor和Filter执行的环境是有一定差别的。

Filter是由servlet容器调用,从请求到响应的过程中可能调用多次。比如请求到达容器,经过Filter1处理之后,再经过Filter2处理,再返回到Filter1处理等。也就是说,它是在请求和响应之间的过滤器,不关心请求的细节,只关心自己要做什么操作。比如,我们可以通过Filter来进行统一安全认证、日志记录、字符编码转换等操作。

Interceptor是在SpringMVC框架中应用的,它与Filter不同的是,它在控制层之前而非之后执行。在执行Handler(Controller)之前,拦截器能够对HTTP请求进行预处理,比如登录校验、权限校验、日志处理等等。通过拦截器的应用,能够实现对请求的更加细致的控制,如不符合要求就直接返回错误信息,而不用像过滤器那样吃掉请求。

二、执行顺序的不同

Interceptor和Filter执行的顺序也是有区别的。

Filter执行的顺序是根据其在web.xml文件里的配置顺序来执行的。具体来说,FilterChain会按照其在web.xml中出现顺序依次执行。如下例子所示:

    <filter>
        <filter-name>myFilter</filter-name>
        <filter-class>com.example.MyFilter</filter-class>
    </filter>
    <filter>
        <filter-name>myFilter2</filter-name>
        <filter-class>com.example.MyFilter2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>myFilter</filter-name>
        <url-pattern>/welcome/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>myFilter2</filter-name>
        <url-pattern>/welcome/*</url-pattern>
    </filter-mapping>

在上面的代码中,myFilter和myFilter2都是针对/welcome/*路径下有效的,它们的执行顺序是按照在web.xml中的定义顺序来执行的。

Interceptor的执行顺序是配置的顺序,可以通过实现Ordered接口来指定执行先后顺序,例如:

    public class LoginInterceptor extends HandlerInterceptorAdapter implements Ordered {
        @Override
        public int getOrder() {
            return 1;
        }
    }
    public class AuthInterceptor extends HandlerInterceptorAdapter implements Ordered {
        @Override
        public int getOrder() {
            return 2;
        }
    }

在这个例子中,LoginInterceptor的顺序是1,AuthInterceptor的顺序是2。也就是说,LoginInterceptor在AuthInterceptor之前被执行。

三、执行效率的不同

Interceptor和Filter执行效率也略有区别。

Filter在SpringMVC框架中并不是必需品,它是由Servlet容器提供的一种标准机制,用于过滤url。由于Filter是由Servlet容器调用,所以会比Interceptor多一些开销。Filter还有一个问题,那就是无法访问Spring的IOC容器。因此,如果需要访问容器中的Bean,就必须使用Interceptor来替代Filter。

Interceptor在SpringMVC框架中是一个重要的组成部分,具体拦截操作是在SpringMVC框架内部完成的,拦截操作的效率也比Filter高。

四、使用场景的不同

Interceptor和Filter的使用场景是不同的。

Filter主要被用于编写一些通用的补丁,比如请求和响应参数的验证和过滤、字符编码处理,安全验证等,还可以用于压缩响应数据等操作。Filter还可以拦截一些Servlet不支持的HTTP请求,并将请求转换成容器能够支持的类型,从而实现更灵活的处理方式。

Interceptor在SpringMVC框架中,主要是用来处理登录权限、事务控制、拦截器跨域访问等操作。

五、两者混合使用

有时候,在开发过程中,我们需要同时使用Interceptor和Filter来做更加详细的过滤操作。这时候,它们的顺序就比较重要了。

如果需要对请求进行多次拦截和处理,那么我们应该遵循Filter-Interceptor-Filter的模式。具体来说,先使用Filter把请求和响应进行预处理,然后再进行拦截器处理,最后再执行Filter进行最终处理。

这个处理流程的原理就是,Filter在正式的请求处理之前进行预先处理,Interceptor可以在请求处理之前和处理之后都进行处理,这样能让我们在处理请求之前进行许多通用的处理,从而为后续的请求操作构建好可靠的环境。

完整的代码示例

使用Filter和Interceptor来对登录进行控制:

    public class LoginFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {}
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            String uri = request.getRequestURI();
            if (uri.startsWith("/login")) { // 登录请求直接放行
                filterChain.doFilter(request, response);
                return;
            }
            HttpSession session = request.getSession();
            if (session == null || session.getAttribute("user") == null) { // 非登录请求校验session是否存在
                response.sendRedirect("/login.html");
                return;
            }
            filterChain.doFilter(request, response);
        }
        @Override
        public void destroy() {}
    }

    public class LoginInterceptor extends HandlerInterceptorAdapter {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            if (request.getRequestURI().startsWith("/login")) { // 登录请求直接放行
                return true;
            }
            HttpSession session = request.getSession();
            if (session == null || session.getAttribute("user") == null) { // 非登录请求校验session是否存在
                response.sendRedirect("/login.html");
                return false;
            }
            return true;
        }
    }

上面的代码中,LoginFilter用于拦截所有的请求,对于/login的请求,跳过校验;不是登录请求,校验session是否已经存在。LoginInterceptor放在#LoginInterceptor"org.springframework.web.servlet.HandlerInterceptor"顶级父类HandlerInterceptorAdapter中,它也做了类似的拦截操作。

总结

Interceptor和Filter都是在web应用程序中进行请求过滤和处理的机制。两者的差别有执行环境不同,执行顺序不同,执行效率不同,使用场景不同等,当需要同时使用它们的时候,应该注意它们的先后关系。对于每一个请求,过滤器执行前必须先执行拦截器,并且过滤器在拦截器之后执行。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。