SpringBoot的本质就是实现了自动装配,解决了Spring研发的配置地域问题。但是它的基础依然是Spring, 对于web研发的基础依然是SpringMVC。因此有必要深入了解Spring, SpringMVC。
对于Spring来说,拦截器和过滤器是非常核心和重要的两个概念。因此本文针对这两个概念进行深入分析,让我们彻底理解拦截器和过滤器。
1. 拦截器和过滤器的区别
过滤器(Filter) | 拦截器(Interceptor) | 总结 |
Filter接口定义在javax.servlet包中 | HandlerInterceptor接口定义在org.springframework.web.servlet包中 | |
Filter定义在web.xml中 | HandlerInterceptor是在应用程序上下文配置的。 | |
Filter只在Servlet前后起作用。Filter通常将请求和响应当做黑盒子,Filter通常不考虑Servlet的实现。 | 拦截器能深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。允许用户接入(hook into)请求的生命周期,在请求过程中获取信息,Interceptor通常和请求更加耦合。 | 在Spring架构的程序中,要有限使用拦截器。几乎所有Filter能做的事情,Interceptor都能够轻松的实现 |
Filter是Servlet规范规定的。 | 拦截器既可以用于Web程序,也可以用于Application、Swing程序中。 | 使用范围不同 |
Filter是在Servlet规范中定义的,是Servlet容器支持的。 | 拦截器是在Spring容器内的,是Spring框架支持的。 | |
Filter不能够使用Spring容器资源。 | 拦截器是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如Service对象、数据源、事务管理等,通过IoC注入到拦截器即可。 | Spring中使用拦截器更容易 |
Filter是被Servlet(就像Tomcat)调用的。 | 拦截器(Interceptor)是被Spring调用的。 | 因此Filter总是优于Interceptor执行。 |
在请求处理和响应过程中过滤器和拦截器等组件的执行流程及关系:
1.请求首先到达Servlet容器,将请求转给web容器。
2.web容器调用Servlet过滤器,然后继续将请求转交给Spring的DispatcherServlet, 请求就转交给Spring上下文。
3.DispatcherServlet就可以调用Spring的拦截器对请求进行拦截处理,最后交给资源控制器。
4.最终有资源控制器结合业务模型进行业务处理,然后沿着4到1一层层朝外对相应进行处理,最终返回给客户端
拦截器的使用
Interceptor的执行顺序大致为:
1.请求到达DispatcherServlet
2.DispatcherServlet发送至Interceptor, 执行preHandle
3.请求到达Controller
4.请求结束后,postHandle执行
Spring中主要通过HandlerInterceptor接口来实现请求的拦截,实现HandlerInterceptor接口需要实现下面三个方法:
1.preHandle(): 在handle执行之前,返回boolean值,true表示继续执行,false为停止执行并返回。
2.postHandle(): 在handle执行之后,可以在返回之前对返回的结果进行修改。
3.afterCompletion(): 在请求完成,视图生成后调用。
Servlet 的 Filter 接口需要实现如下方法:
void init(FilterConfig paramFilterConfig) – 当容器初始化 Filter 时调用,该方法在 Filter 的生命周期只会被调用一次,一般在该方法中初始化一些资源,FilterConfig 是容器提供给 Filter 的初始化参数,在该方法中可以抛出 ServletException 。init 方法必须执行成功,否则 Filter 可能不起作用,出现以下两种情况时,web 容器中 Filter 可能无效:
1.抛出 ServletException
2.超过 web 容器定义的执行时间。
doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) – Web 容器每一次请求都会调用该方法。该方法将容器的请求和响应作为参数传递进来, FilterChain 用来调用下一个 Filter。
void destroy() – 当容器销毁 Filter 实例时调用该方法,可以在方法中销毁资源,该方法在 Filter 的生命周期只会被调用一次。