前言
转载一篇介绍 Spring 的 Interceptor 和 Filter 的文章,转自:http://einverne.github.io/post//08/spring-interceptor-vs-filter.html。
这篇文章感觉讲的不错,还需要深度去理解和分析一下,所以这里摘抄一下原文,同时记录一下笔记,同时感觉有些格式或者标点符号或者大小写存在一点问题,也随之修改一下。
正文
Spring Interceptor vs Filter 拦截器和过滤器区别
Posted on 08/14/by Ein Verne|View revision history
Spring 的 Interceptor(拦截器)与 Servlet 的 Filter 有相似之处,都能实现权限检查、日志记录等。不同的是:
Interceptor 使用
Interceptor 的执行顺序大致为:
请求到达 DispatcherServletDispatcherServlet 发送至 Interceptor ,执行 preHandle请求达到 Controller请求结束后,postHandle 执行
Spring 中主要通过 HandlerInterceptor 接口来实现请求的拦截,实现 HandlerInterceptor 接口需要实现下面三个方法:
preHandle()– 在handler执行之前,返回 boolean 值,true 表示继续执行,false 为停止执行并返回。postHandle()– 在handler执行之后, 可以在返回之前对返回的结果进行修改。afterCompletion()– 在请求完全结束后调用,可以用来统计请求耗时等等。
统计请求耗时
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.log4j.Logger;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;public class ExecuteTimeInterceptor extends HandlerInterceptorAdapter{private static final Logger logger = Logger.getLogger(ExecuteTimeInterceptor.class);//before the actual handler will be executedpublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler)throws Exception {long startTime = System.currentTimeMillis();request.setAttribute("startTime", startTime);return true;}//after the handler is executedpublic void postHandle(HttpServletRequest request, HttpServletResponse response,Object handler, ModelAndView modelAndView)throws Exception {long startTime = (Long)request.getAttribute("startTime");long endTime = System.currentTimeMillis();long executeTime = endTime - startTime;//modified the exisitng modelAndViewmodelAndView.addObject("executeTime",executeTime);//log itif(logger.isDebugEnabled()){logger.debug("[" + handler + "] executeTime : " + executeTime + "ms");}}}
例子来源mkyong
使用mvc:interceptors标签来声明需要加入到SpringMVC拦截器链中的拦截器
<mvc:interceptors> <!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 --> <bean class="pany.app.web.interceptor.AllInterceptor"/> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/parent/**"/> <bean class="pany.authorization.interceptor.SecurityInterceptor" /> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/parent/**"/> <bean class="pany.authorization.interceptor.SecuritySystemInterceptor" /> </mvc:interceptor> </mvc:interceptors>
可以利用 mvc:interceptors 标签声明一系列的拦截器,然后它们就可以形成一个拦截器链,拦截器的执行顺序是按声明的先后顺序执行的,先声明的拦截器中的 preHandle 方法会先执行,然而它的 postHandle 方法和 afterCompletion 方法却会后执行。
在 mvc:interceptors 标签下声明 Interceptor 主要有两种方式:
直接定义一个 Interceptor 实现类的 bean 对象。使用这种方式声明的 Interceptor 拦截器将会对所有的请求进行拦截。使用 mvc:interceptor 标签进行声明。使用这种方式进行声明的 Interceptor 可以通过 mvc:mapping 子标签来定义需要进行拦截的请求路径。
经过上述两步之后,定义的拦截器就会发生作用对特定的请求进行拦截了。
Filter 使用
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 的生命周期只会被调用一次。
pany.filter.FrequencyLimitFilterFrequencyLimitFilter/login/*
Filter 和 Interceptor 的一些用途
Authentication FiltersLogging and Auditing FiltersImage conversion FiltersData compression FiltersEncryption FiltersTokenizing FiltersFilters that trigger resource access eventsXSL/T filtersMime-type chain FilterRequest Filters 可以:
执行安全检查 perform security checks格式化请求头和主体 reformat request headers or bodies审查或者记录日志 audit or log requests根据请求内容授权或者限制用户访问 Authentication-Blocking requests based on user identity.根据请求频率限制用户访问
Response Filters 可以:
压缩响应内容,比如让下载的内容更小 Compress the response stream追加或者修改响应 append or alter the response stream创建或者整体修改响应 create a different response altogether根据地方不同修改响应内容 Localization-Targeting the request and response to a particular locale.
reference
//06/08/filter-vs-interceptor//a/8006315/187↩
个人补充
还有几篇帖子可以参考:
1./jersey-filters-interceptors,这个网站的内容都很不错。
个人的一些认知,interceptor的概念似乎是struts引入的,后来Spring参考struts自己实现了这个功能。
这个图摘自这里,介绍了 Filter 在整个请求处理过程中的位置。