Spring拦截器Interceptor与Servlet过滤器Filter详解

一、先说结论

1.拦截器Interceptor与过滤器Filter的区别

《JAVA编程思想》截图
在这里插入图片描述
两者最大的区别在于:过滤器是在 Servlet 规范中定义的,是由 Servlet 容器支持的;拦截器是在 Spring 容器内的,由 Spring 框架支持。

因此,作为 Spring 的一个组件,拦截器可以通过IOC容器进行管理,获取其中的各个 bean 实例,对 spring 中的各种资源、对象,如 Service 对象、数据源、事务管理等进行调用;而过滤器则不能。

总的来说,两者主要在如下方面存在着差异 :

  1. 过滤器是基于函数的回调,而拦截器是基于 Java 反射机制的
  2. 过滤器可以修改 request,而拦截器则不能(待证,Intercepter的preHandle可以向request添加attribute,不知道这个结论是否是个人的理解错了)
  3. 过滤器需要在 servlet 容器中实现,拦截器可以适用于 JavaEE、JavaSE 等各种环境
  4. 拦截器可以调用 IOC 容器中的各种依赖,而过滤器不能
  5. 过滤器只能在请求的前后使用,而拦截器可以详细到每个方法

2.拦截器链与过滤器链的执行顺序

Filter 链执行顺序

1.根据web.xml中配置的顺序决定过滤器的先后关系

2.在doFilter方法中,位于FilterChain.doFilter方法之前的代码先于Servlet执行

3.位于FilterChain.doFilter方法之后的代码在Servlet执行之后执行
在这里插入图片描述

Interceptor 执行顺序

1.根据springmvc.xml中配置的顺序决定拦截器的先后关系
在这里插入图片描述

3.拦截器与过滤器的执行时机

过滤器先于拦截器执行
在这里插入图片描述
在这里插入图片描述

4.拦截器与过滤器的适用场景

拦截器Interceptor

  1. 日志记录 :机率请求信息的日志,以便进行信息监控、信息统计等等
  2. 权限检查 :对用户的访问权限,认证,或授权等进行检查
  3. 性能监控 :通过拦截器在进入处理器前后分别记录开始时间和结束时间,从而得到请求的处理时间
  4. 通用行为 :读取 cookie 得到用户信息并将用户对象放入请求头中,从而方便后续流程使用

过滤器Filter

为shiro权限过滤器,编码过滤器,微信接口过滤器,上传文件过滤器等。
在这里插入图片描述

二、拦截器与过滤器的使用及验证

1.配置Filter

新建TestFilter类,实现过滤器中的逻辑

package com.framework;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 @author sunhongmin 2019-12-19
 Filter执行类,实现Filter接口,覆写init、doFilter、destory方法
*/
public class TestFilter implements Filter{

	@Override
	public void destroy() {
		//Filter销毁
   	//web容器调用destroy方法销毁Filter。destroy方法在Filter的生命周期中仅执行一次。在destroy方法中,可以释放过滤器使用的资源。
		System.out.println("Filter1 destroy");
	}

	@Override
	public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
			throws IOException, ServletException {
		//Filter 先拦截request, doFilter放行, response响应回来, Filter再次拦截 ,执行doFilter()后面的代码
		//arg0.setAttribute("key0", "from Filter doFilter");
		System.out.println("Filter1 doFilter1");//doFilter之前的代码,用于对请求进行处理
		arg2.doFilter(arg0, arg1);
		System.out.println("Filter1 doFilter2");//doFilter之后的代码,用于对请求响应进行处理
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		//Filter初始化
		// web应用程序启动时,web服务器将创建Filter的实例对象,并调用其init方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作,filter对象只会创建一次,init方法也只会执行一次。通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
		System.out.println("Filter1 init");
	}

}

在web.xml配置过滤器名称,过滤路径与class路径,拦截所有请求

<!--配置过滤器-->  
  <filter>  
      <filter-name>FilterTest</filter-name>  
      <filter-class>com.framework.TestFilter</filter-class>  
  </filter>  
  <!--映射过滤器-->  
  <filter-mapping>  
      <filter-name>FilterTest</filter-name>  
      <!--“/*”表示拦截所有的请求 -->  
      <url-pattern>/*</url-pattern>  
  </filter-mapping>

2.配置Interceptor

新建TestInterceptor拦截器类,实现HandlerInterceptor接口

package com.framework;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class TestIntercepter implements HandlerInterceptor{
	/**
	 * 	preHandle
		调用时间:Controller方法处理之前
		执行顺序:链式Intercepter情况下,Intercepter按照声明的顺序一个接一个执行
		若返回false,则中断执行,注意:不会进入afterCompletion
		处理参数,校验权限,决定是否继续执行
		
		postHandle
		调用前提:preHandle返回true
		调用时间:Controller方法处理完之后,DispatcherServlet进行视图的渲染之前,也就是说在这个方法中你可以对ModelAndView进行操作
		执行顺序:链式Intercepter情况下,Intercepter按照声明的顺序倒着执行。
		备注:postHandle虽然post打头,但post、get方法都能处理
		一般可以通过它对 Controller 处理之后的 ModelAndView 对象进行操作。
		
		afterCompletion
		调用前提:preHandle返回true
		调用时间:DispatcherServlet进行视图的渲染之后
		在整个请求处理完成(包括视图渲染)后执行,主要用来进行一些资源的清理工作。
	 * */
	@Override
	public void afterCompletion(HttpServletRequest req, HttpServletResponse arg1, Object arg2, Exception arg3)
			throws Exception {
		//System.out.println("key2:-->"+req.getAttribute("key2"));
		System.out.println(" Intercepter1 doAfterCompletion...");
	}

	@Override
	public void postHandle(HttpServletRequest req, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
			throws Exception {
		//System.out.println("key2:-->"+req.getAttribute("key2"));
		System.out.println(" Intercepter1 doPostHandle...");
	}

	@Override
	public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
		//arg0.setAttribute("key1", "from intercepter preHandle");
		System.out.println(" Intercepter1 doPreHandle...");
		return true;
	}

}

配置springmvc.xml文件

<mvc:interceptors>
        <mvc:interceptor>
            <!-- /** 表示拦截所有请求-->
            <mvc:mapping path="/**"/>
            <!-- 为了排除干扰,将静态资源请求排除,如果前后端分离可以忽略 -->
            <mvc:exclude-mapping path="/js/**" />
            <mvc:exclude-mapping path="/css/**" />
            <mvc:exclude-mapping path="/images/**" />
            <bean class="com.framework.TestIntercepter"/>
        </mvc:interceptor>
</mvc:interceptors>        

3.验证执行顺序

为了查看拦截器与过滤器执行链的总体顺序,加入TestFilter2与TestInterceptor2
web.xml
在这里插入图片描述
在这里插入图片描述
查看执行结果
在这里插入图片描述

总结

Filter只在Servlet前后起作用,而拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。所以在spring结构的程序中,要优先使用拦截器。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章