过滤器(Filter)与拦截器(Interceptor)对比
1.过滤器
1.1定义功能
定义:Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,可以用来转换HTTP请求,响应和头信息。它不能产生一个请求或者响应,只是修改对某一资源的请求或响应;
功能:通过Filter技术,对web服务器管理的所有web资源:例如Jsp,Servlet, 静态图片文件或静态html文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等。
1.2工作过程
Filter接口中有一个doFilter()方法,当实现好Filter接口,并配置对哪个web资源进行拦截后,Web服务器每次在调用web资源的service方法之前,都会先调用一下Filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
调用目标资源之前,让一段代码执行。
是否调用目标资源(通过是否调用FilterChain对象的doFilter()方法实现)。
调用目标资源之后,让一段代码执行。
web服务器在调用doFilter()方法时,会传递一个FilterChain对象进来,FilterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter()方法,如果调用FilterChain对象的doFilter()方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。如果不调用FilterChain对象的doFilter()方法,则web资源不会被访问。
1.3 生命周期
Filter的生命周期和Servlet一样,Filter的创建和销毁也是由web服务器负责。
1.在应用启动的时候就进行加载Filter类。
2.容器创建好Filter对象实例后,调用init()方法,。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。
3.当用户访问的资源正好被Filter的url-pattern拦截时,容器会取出Filter类调用doFilter()方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法。
4.当应用服务被停止或重新装载了,则会执行Filter的destroy方法,Filter对象销毁。
注意:init方法与destroy方法只会直接一次。
1.4 代码实现
Filter开发分为2步:
1.编写java类实现Filter接口,并重写其doFilter()方法。
public class FilterTest implements Filter { //对filter进行一个初始化 @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("Filter is initing please wait"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("UTF-8"); servletResponse.setCharacterEncoding("UTF-8"); //调用servlet方法前(访问web资源前执行的代码,相当于图中的code1) servletResponse.setContentType("text/html;charset=UTF-8"); System.out.println("filter before service() do"); filterChain.doFilter(servletRequest,servletResponse); //调用servlet方法后(获得web资源后执行的代码,相当于图中的code2) System.out.println("filter after service() do"); } //调用destroy方法,filter被摧毁,生命周期结束 @Override public void destroy() { System.out.println("filter is destroy"); } }
2.在web.xml 文件中使用<filter>和<filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源。注册和映射的配置是必不可少的。
<!-- 过滤器配置一--> <filter> <filter-name>FilterTest</filter-name> <!-- 要填写全类名--> <filter-class>com.zeron.anoservlet.FilterTest</filter-class> </filter> <filter-mapping> <filter-name>FilterTest</filter-name> <!-- /*表示拦截所有请求 --> <url-pattern>/*</url-pattern> </filter-mapping>
3.在配置filter时,可以使用<init-param>为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。通过filterConfig对象的方法,就可获得:
String getFilterName():得到filter的名称。
String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
public ServletContext getServletContext():返回Servlet上下文对象的引用。
1.5 特性总结
应用场景:获取用户身份,参数校验,设置字符编码,过滤敏感词汇,权限访问控制等等
总结:所谓过滤器就是对请求进行过滤,作用在servlet之前,它是系统级别的过滤,在实现上基于函数回调,依赖于servlet容器。
2.拦截器
2.1定义功能
定义:Java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。
功能:可以进行权限验证,审计日志等。
2.2工作过程
①程序先执行preHandle()方法,如果该方法的返回值为true,则程序会继续向下执行处理其中的方法,否则将不再向下执行。
②在业务处理器(即控制器Controller类)处理完请求后,会执行postHandle()方法,然后会通过DispatcherServlet向客户端返回响应。
③处理完所有业务后,才会执行afterCompletion()方法。
生命周期:加载配置文件后初始化拦截器,当有对Action的请求的时候,调用interceptor方法,最后也是根据服务器停止进行销毁;
对于多个拦截器的执行顺序(以2个为例)
1.请求指定Controller的url
2.拦截器1的preHandle():处理请求之前的业务,return true时
拦截器2的preHandle():处理请求之前的业务,return true时
3.执行Controller的url
4.拦截器2postHandle():处理响应之前业务
拦截器1postHandle():处理响应之前业务
5.视图渲染
6.拦截器2的afterCompletion():处理外所有业务之后执行【释放资源等】
拦截器1的afterCompletion():处理外所有业务之后执行【释放资源等】
2.3 特性总结
Java里的拦截器提供的是非系统级别的拦截,就覆盖面来说,不如过滤器强大,但是更有针对性。
Java中的拦截器是基于Java反射机制实现的,更准确的划分,应该是基于JDK实现的动态代理。它依赖于具体的接口,在运行期间动态生成字节码。
拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截然后再之前或
者之后加入某些操作。
3.对比总结:
3.1 过滤器和拦截器的执行顺序
3.2区别对比(简单理解过滤器为取你所想取,拦截器为拒你所想拒)
1.拦截器是基于java的反射机制的,而过滤器是基于函数回调。
2.拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
3.拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
4.拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
5.在action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次。
3.3其他补充:Tomcat中的filter分析
Tomcat中的Filter 是采用责任链设计模式。
首先通过StandardWrapperValve.invoke()方法创建一个过滤器链,并把待执行的 servlet 对象存放到过滤器链中。
如果servlet对象和过滤器链都不为空,则开始调用filterChain的doFilter()方法。该方法有三个参数request对象,response对象,filter chain对象。如图
pos:为过滤器链中当前执行的过滤器下标。 n:过滤器链中的过滤器个数。
每执行一个过滤器则把过滤器链中的post+1(下标),直到所有的过滤器的doFilter方法都调用成功。
这行代码是整个责任链模式的精妙之处,进入doFilter()方法后,,首先会对request请求进行处理, 然后调用了过滤器链的doFilter()方法.,让每个过滤器可以调用过滤器链本身执行下一个过滤器。
为什么要调用过滤器链本身?因为当调用过滤器本身后, 程序将跳转回到过滤器链的doFilter方法执行, 这时pos为1, 也就是拿到第二个过滤器, 然后继续处理。
正是由于这个跳转, 使得过滤器中对response的处理暂时无法执行, 它必须等待上面的对过滤器链的方法返回才能被执行。执行流程如下图:
参考链接:https://blog.csdn.net/ZeronGod/article/details/119705023
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
2021-07-14 JDK常用分析工具
2021-07-14 mysql表碎片清理和表空间收缩
2017-07-14 (转)24种设计模式大全
2016-07-14 Docker remote API简单配置使用
2016-07-14 Docker建立本地Registry