OncePerRequestFilter

来源:http://ully.iteye.com/blog/1334925

在spring中,filter都默认继承OncePerRequestFilter,但为什么要这样呢?

OncePerRequestFilter顾名思义,他能够确保在一次请求只通过一次filter,而不需要重复执行。

Java代码 复制代码  收藏代码
  1. public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)   
  2.             throws ServletException, IOException {   
  3.   
  4.         if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {   
  5.             throw new ServletException("OncePerRequestFilter just supports HTTP requests");   
  6.         }   
  7.         HttpServletRequest httpRequest = (HttpServletRequest) request;   
  8.         HttpServletResponse httpResponse = (HttpServletResponse) response;   
  9.   
  10.         String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();   
  11.         if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {   
  12.             // Proceed without invoking this filter...   
  13.             filterChain.doFilter(request, response);   
  14.         }   
  15.         else {   
  16.             // Do invoke this filter...   
  17.             request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);   
  18.             try {   
  19.                 doFilterInternal(httpRequest, httpResponse, filterChain);   
  20.             }   
  21.             finally {   
  22.                 // Remove the "already filtered" request attribute for this request.   
  23.                 request.removeAttribute(alreadyFilteredAttributeName);   
  24.             }   
  25.         }   
  26.     }  
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
			throw new ServletException("OncePerRequestFilter just supports HTTP requests");
		}
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;

		String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
		if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {
			// Proceed without invoking this filter...
			filterChain.doFilter(request, response);
		}
		else {
			// Do invoke this filter...
			request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
			try {
				doFilterInternal(httpRequest, httpResponse, filterChain);
			}
			finally {
				// Remove the "already filtered" request attribute for this request.
				request.removeAttribute(alreadyFilteredAttributeName);
			}
		}
	}

大家常识上都认为,一次请求本来就只过一次,为什么还要由此特别限定呢,呵呵实际上我们常识和实际的实现并不真的一样,经过一番查阅后,此方式是为了兼容不同的web container,特意而为之(jsr168),也就是说并不是所有的container都像我们期望的只过滤一次,servlet版本不同,表现也不同:。

 写道
/**
* Filter base class that guarantees to be just executed once per request,
* on any servlet container. It provides a {@link #doFilterInternal}
* method with HttpServletRequest and HttpServletResponse arguments.
*
* <p>The {@link #getAlreadyFilteredAttributeName} method determines how
* to identify that a request is already filtered. The default implementation
* is based on the configured name of the concrete filter instance.
*
* @author Juergen Hoeller
* @since 06.12.2003
*/

如,servlet2.3与servlet2.4也有一定差异

 写道
在servlet-2.3中,Filter会过滤一切请求,包括服务器内部使用forward转发请求和<%@ include file="/index.jsp"%>的情况。

到了servlet-2.4中Filter默认下只拦截外部提交的请求,forward和include这些内部转发都不会被过滤,但是有时候我们需要 forward的时候也用到Filter。

 因此,为了兼容各种不同的运行环境和版本,默认filter继承OncePerRequestFilter是一个比较稳妥的选择。

猜你喜欢

转载自dongxylove.iteye.com/blog/2247533