您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

过滤器与拦截器的N个区别,别傻傻分不清了

时间:2020-12-29 11:12:51  来源:  作者:

Spring的拦截器与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,都能实现权限检查、日志记录等。但它们之间又有不少区别,很多朋友工作多年,可能还没有深刻的了解它们的具体使用以及它们之间的区别。本文带大家全面了解一下它们的使用、实现机制以及区别。

过滤器(Filter)的详解及使用

过滤器(Filter)属于Servlet的范畴,可以认为是Servlet的一种“加强版”,通过实现JAVAx.servlet.Filter接口来实现功能。主要用于对用户请求进行预处理,是个典型的处理链。通常使用场景:检查用户授权、记录日志信息、解码、过滤字符编码等。

基本工作原理:配置完过滤器及需要拦截的请求,当请求到来时,通过过滤器提供的方法可以对请求或响应(Request、Response)统一处理。比如,可判断用户是否登录,是否拥有请求的访问权限等。在Web应用启动时,过滤器仅会被初始化一次,便可处理后续请求,只有Web应用停止或重新部署时才能销毁。

使用Filter完整的流程是:Filter对用户请求进行“预处理”,接着将请求交给Servlet进处理并生成响应,最后Filter再对服务器响应进行“后处理”。

上述流程具体到类的处理就是:

1、Filter在ServletRequest到达Servlet之前,拦截客户的ServletRequest;

2、根据需要检查ServletRequest,也可修改ServletRequest头和数据;

3、在ServletResponse到达客户端之前,拦截ServletResponse;

4、根据需要检查HttpServletResponse,也可修改HttpServletResponse头和数据。

创建Filter必须实现javax.servlet.Filter接口,该接口定义了3个方法:

  • void init(FilterConfig filterConfig):容器启动初始化Filter时会被调用,整个生命周期只会被调用一次。可用于完成Filter的初始化。
  • void doFilter(ServletRequest request, ServletResponse response,FilterChain chain):实现过滤功能,就是通过该方法对每个请求增加额外的处理。通过其参数FilterChain调用下一个过滤器。
  • void destroy():用于Filter销毁前,完成某些资源的回收。

其中,doFilter方法便是实现对用户请求进行预处理(ServletRequest request)和对服务器响应进行后处理(ServletResponse response)的方法。预处理和后处理的分界线为是否调用了chain.doFilter()。在执行该方法之前,是对用户请求进行预处理,在执行该方法之后,是对服务器响应进行后处理。

下面以具体的实现代码来展示一下:

public class LogFilter 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);
        System.out.println("Filter 后处理");
    }

    @Override
    public void destroy() {
        System.out.println("容器销毁");
    }
}

关于Filter的使用在普通的Web项目中可在web.xml中配置:

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>com.secbro2.learn.filter.LogFilter</filter-class>
    <async-supported>true</async-supported>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mApping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

如果是SpringBoot项目,首先使用@Component将LogFilter实例化,然后通过如下配置文件,进行具体的配置:

@Configuration
public class FilterConfig {

    @Resource
    private LogFilter logFilter;

    @Bean
    public FilterRegistrationBean<Filter> registerAuthFilter() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(logFilter);
        registration.addUrlPatterns("/*");
        registration.setName("authFilter");
        // 值越小,Filter越靠前
        registration.setOrder(1);
        return registration;
    }
}

定义一个Contoller,然后依次执行启动项目、访问Controller、关闭项目,打印的日志信息依次为:

Filter 初始化
---以上为启动项目时打印---
Filter 预处理
Controller中处理业务逻辑
Filter 后处理
---以上为访问Controller时打印---
容器销毁
---以上为关闭服务时打印---

拦截器(Interceptor)的详解及使用

拦截器,在AOP(Aspect-Oriented Programming)中用于某个方法或字段被访问之前进行拦截,然后在其之前或之后加入某些操作。拦截器作为动态拦截Action调用的对象,它提供了一种机制使开发者可以在Action执行前后定义可执行的代码,也可以在Action执行前阻止其执行。

拦截器将Action共用的行为独立出来,在Action执行前后执行。常见的应用场景比如权限管理、日志服务等。

在Spring MVC当中要使用拦截器需要实现org.springframework.web.servlet.HandlerInterceptor接口,该接口定义了如下三个方法:

(1)preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法,会在请求处理之前被调用。SpringMVC中的Interceptor是链式调用的,可以存在多个Interceptor。Interceptor的调用会依据声明顺序依次执行,最先执行的都是preHandle方法,可在该方法中进行一些前置(预)处理,也可进行判断来决定是否要继续执行。当返回为false 时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时,会继续调用下一个Interceptor的preHandle方法,执行完最后一个Interceptor后会调用当前请求的Controller方法。

(2 )postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,会在Controller方法调用之后,DispatcherServlet进行渲染视图之前被调用,所以可以对Controller处理之后的ModelAndView对象进行操作。postHandle方法被调用的方向跟preHandle是相反的,先声明的Interceptor的postHandle方法反而会后执行。

(3 )afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法,会在整个请求结束之后被调用,也就是在DispatcherServlet渲染了对应的视图之后执行。这个方法的主要是用于进行资源清理。

来看一个具体的示例:

@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("Interceptor preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        System.out.println("Interceptor postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("Interceptor afterCompletion");
    }
}

对应LoginInterceptor需添加到Spring MVC当中:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Resource
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**");
    }
}

这里拦截所有的请求,执行对应的Controller之后,会看到打印如下信息:

Interceptor preHandle
Controller中处理业务逻辑
Interceptor postHandle
Interceptor afterCompletion

很明显可以看到,当一个请求过来之后,会先后执行preHandle方法、Controller中的业务、postHandle方法和afterCompletion方法。

过滤器与拦截器的区别

经过上面的学习,我们已经大概了解了过滤器和拦截器的基本使用和功能,想必已经感觉到它们之间的一些区别了。先看一张图,可以更加明显的看出过滤器和拦截器在使用过程中所处的位置和使用的时机。

过滤器与拦截器的N个区别,别傻傻分不清了

 

汇总一下就是:

1、使用范围与规范不同:Filter是Servlet规范中定义的,只能用于Web程序中,依赖于Servlet容器。拦截器是Spring的组件,可用于Web程序、Application、Swing等程序,不依赖Servlet容器。

2、使用资源不同:拦截器可以使用Spring里的任何资源、对象,例如Service对象、数据源、事务管理等,通过IOC注入到拦截器即可;而Filter则不能。

3、作用范围不同:Filter在只在Servlet前后起作用。而拦截器能够深入到方法前后、异常抛出前后,对Action请求其作用,可以访问Action上下文、值栈里的对象等,具有更大的弹性。因此,在Spring框架的过程中,要优先使用拦截器。而滤器则可以对几乎所有的请求起作用。

4、实现机制不同:拦截器是基于java的反射机制的,而过滤器是基于函数回调。

上面介绍了过滤器和拦截器的基本不同之处,这里再对上面的图进一步细化,可得到下图:

过滤器与拦截器的N个区别,别傻傻分不清了

 

通过上图,我们可以进一步看到拦截器和过滤器的方法在整个请求过程中所处的位置。

小结

通过上面的学习,想必大家已经掌握了过滤器和拦截器的基本使用。最后补充一下,什么时候适合使用过滤器,什么时候又适合使用拦截器呢?当需要过滤掉其中的部分信息,只留一部分时,就用过滤器;当需要对其流程进行更改,做相关的记录时用拦截器。



Tags:过滤器   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
Spring的拦截器与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,都能实现权限检查、日志记录等。但它们之间又有不少区别,很多朋友工作多年,可能还没有深刻的了解它...【详细内容】
2020-12-29  Tags: 过滤器  点击:(169)  评论:(0)  加入收藏
你需要一个 WebSecurityConfigurerAdapter 来对用户提供安全的校验,确保用户能够访问必要的资源。一个基于 Spring Boot 的应用程序将会帮你完成安全的校验(通过在 HTTP 的基...【详细内容】
2020-10-16  Tags: 过滤器  点击:(65)  评论:(0)  加入收藏
布隆过滤器(BloomFilter)类似于hash set,用来判断元素是否在集合中。但是与hash set区别是:布隆过滤器不需要存储元素值,就能判断元素是否在集合中。说一下布隆过滤器优缺点: 优点...【详细内容】
2020-09-29  Tags: 过滤器  点击:(121)  评论:(0)  加入收藏
作者:jack_xujuejin.im/post/5e9c110151882573793e8940不知道从什么时候开始,本来默默无闻的布隆过滤器一下子名声大燥,在面试中面试官问到怎么避免缓存穿透,你的第一反应可能就...【详细内容】
2020-05-13  Tags: 过滤器  点击:(43)  评论:(0)  加入收藏
为什么引入我们的业务中经常会遇到穿库的问题,通常可以通过缓存解决。如果数据维度比较多,结果数据集合比较大时,缓存的效果就不明显了。因此为了解决穿库的问题,我们引入Bloom...【详细内容】
2020-05-05  Tags: 过滤器  点击:(46)  评论:(0)  加入收藏
Redis概述:Redis是一个开源的Key-Value存储系统,其中Value支持String、list、set、hash、zset五种数据结构,这些数据都支持push/pop、add/remove、取交集并集、排序等丰富的操...【详细内容】
2020-01-17  Tags: 过滤器  点击:(195)  评论:(0)  加入收藏
虽然我们不是在安全公司工作,但喜欢参加Hackerone上的漏洞悬赏项目,喜欢寻找漏洞。而最近发现的漏洞让我感觉javascript代码中的注入漏洞的确会让人防不胜防。我们在目标网站...【详细内容】
2019-10-16  Tags: 过滤器  点击:(98)  评论:(0)  加入收藏
在项目开发中,我们经常会遇到去重问题。比如:判断一个人有没有浏览过一篇文章,判断一个人当天是否登录过某个系统,判断一个ip是否发过一个请求,等等。...【详细内容】
2019-10-08  Tags: 过滤器  点击:(152)  评论:(0)  加入收藏
概述布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数,布隆过滤器可以用于检索一个元素是否在一个集合中。如果想要判...【详细内容】
2019-08-30  Tags: 过滤器  点击:(210)  评论:(0)  加入收藏
URL去重应用URL去重广泛应用于网络爬虫方面,主要体现在以下两点: 实现增量爬虫时,需要判断哪些网页已经爬取了,哪些网页是新产生的,对新产生的网页,增量爬虫需要抓取其内容; 避免爬...【详细内容】
2019-08-26  Tags: 过滤器  点击:(310)  评论:(0)  加入收藏
▌简易百科推荐
一、Redis使用过程中一些小的注意点1、不要把Redis当成数据库来使用二、Arrays.asList常见失误需求:把数组转成list集合去处理。方法:Arrays.asList 或者 Java8的stream流式处...【详细内容】
2021-12-27  CF07    Tags:Java   点击:(3)  评论:(0)  加入收藏
文章目录 如何理解面向对象编程? JDK 和 JRE 有什么区别? 如何理解Java中封装,继承、多态特性? 如何理解Java中的字节码对象? 你是如何理解Java中的泛型的? 说说泛型应用...【详细内容】
2021-12-24  Java架构师之路    Tags:JAVA   点击:(5)  评论:(0)  加入收藏
大家好!我是老码农,一个喜欢技术、爱分享的同学,从今天开始和大家持续分享JVM调优方面的经验。JVM调优是个大话题,涉及的知识点很庞大 Java内存模型 垃圾回收机制 各种工具使用 ...【详细内容】
2021-12-23  小码匠和老码农    Tags:JVM调优   点击:(11)  评论:(0)  加入收藏
前言JDBC访问Postgresql的jsonb类型字段当然可以使用Postgresql jdbc驱动中提供的PGobject,但是这样在需要兼容多种数据库的系统开发中显得不那么通用,需要特殊处理。本文介绍...【详细内容】
2021-12-23  dingle    Tags:JDBC   点击:(12)  评论:(0)  加入收藏
Java与Lua相互调用案例比较少,因此项目使用需要做详细的性能测试,本内容只做粗略测试。目前已完成初版Lua-Java调用框架开发,后期有时间准备把框架进行抽象,并开源出来,感兴趣的...【详细内容】
2021-12-23  JAVA小白    Tags:Java   点击:(10)  评论:(0)  加入收藏
Java从版本5开始,在 java.util.concurrent.locks包内给我们提供了除了synchronized关键字以外的几个新的锁功能的实现,ReentrantLock就是其中的一个。但是这并不意味着我们可...【详细内容】
2021-12-17  小西学JAVA    Tags:JAVA并发   点击:(10)  评论:(0)  加入收藏
一、概述final是Java关键字中最常见之一,表示“最终的,不可更改”之意,在Java中也正是这个意思。有final修饰的内容,就会变得与众不同,它们会变成终极存在,其内容成为固定的存在。...【详细内容】
2021-12-15  唯一浩哥    Tags:Java基础   点击:(14)  评论:(0)  加入收藏
1、问题描述关于java中的日志管理logback,去年写过关于logback介绍的文章,这次项目中又优化了下,记录下,希望能帮到需要的朋友。2、解决方案这次其实是碰到了一个问题,一般的情况...【详细内容】
2021-12-15  软件老王    Tags:logback   点击:(17)  评论:(0)  加入收藏
本篇文章我们以AtomicInteger为例子,主要讲解下CAS(Compare And Swap)功能是如何在AtomicInteger中使用的,以及提供CAS功能的Unsafe对象。我们先从一个例子开始吧。假设现在我们...【详细内容】
2021-12-14  小西学JAVA    Tags:JAVA   点击:(21)  评论:(0)  加入收藏
一、概述观察者模式,又可以称之为发布-订阅模式,观察者,顾名思义,就是一个监听者,类似监听器的存在,一旦被观察/监听的目标发生的情况,就会被监听者发现,这么想来目标发生情况到观察...【详细内容】
2021-12-13  唯一浩哥    Tags:Java   点击:(16)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条