OncePerRequestFilter-源码解析
在spring中,filter都默认继承OncePerRequestFilter,但为什么要这样呢?OncePerRequestFilter顾名思义,他能够确保在一次请求只通过一次filter,而不需要重复执行。/*** 过滤器基类,旨在确保每个请求调度在任何servlet容器上执行一次执行。* 它提供了一个带有HttpServletRequest和HttpServletResp...
·
在spring中,filter都默认继承OncePerRequestFilter,但为什么要这样呢?
OncePerRequestFilter顾名思义,他能够确保在一次请求只通过一次filter,而不需要重复执行。
/**
* 过滤器基类,旨在确保每个请求调度在任何servlet容器上执行一次执行。
* 它提供了一个带有HttpServletRequest和HttpServletResponse参数的{@link #doFilterInternal}方法。
*/
public abstract class OncePerRequestFilter extends GenericFilterBean {
//附加到“已过滤”请求属性的过滤器名称的后缀。
public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";
//这个doFilter实现存储“已经过滤”的请求属性,如果该属性已经存在,则不进行再次过滤。
//@see #getAlreadyFilteredAttributeName
@Override
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();
boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;
if (hasAlreadyFilteredAttribute || skipDispatch(httpRequest) || shouldNotFilter(httpRequest)) {
// 继续而不调用此过滤器...
filterChain.doFilter(request, response);
}
else {
// 调用这个过滤器…
request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
try {
doFilterInternal(httpRequest, httpResponse, filterChain);
}
finally {
// 删除此请求的“已过滤”请求属性。
request.removeAttribute(alreadyFilteredAttributeName);
}
}
}
/**
* 返回表明请求已被过滤的请求属性的名称。
*/
protected String getAlreadyFilteredAttributeName() {
// 如果没有可用的过滤器名,则为{@code null}
String name = getFilterName();
if (name == null) {
name = getClass().getName();
}
return name + ALREADY_FILTERED_SUFFIX;
}
private boolean skipDispatch(HttpServletRequest request) {
if (isAsyncDispatch(request) && shouldNotFilterAsyncDispatch()) {
return true;
}
if (request.getAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE) != null && shouldNotFilterErrorDispatch(){
return true;
}
return false;
}
/**
* 在Servlet 3.0中引入的调度器类型{@code javax.servlet.DispatcherType.ASYNC}意味着一个过滤器可以在一个请求过程中在多个线
* 程中被调用。 如果过滤器当前在异步分派中执行,则此方法返回{true}。
*/
protected boolean isAsyncDispatch(HttpServletRequest request) {
return WebAsyncUtils.getAsyncManager(request).hasConcurrentResult();
}
/**
* 请求处理是否处于异步模式,意味着退出当前线程后不会提交响应。
*/
protected boolean isAsyncStarted(HttpServletRequest request) {
return WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted();
}
/**
* 可以在子类中覆盖自定义过滤控件,返回{true}以避免过滤给定的请求。 默认实现总是返回{@code false}。
*/
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return false;
}
protected boolean shouldNotFilterAsyncDispatch() {
return true;
}
protected boolean shouldNotFilterErrorDispatch() {
return true;
}
/**
* 与{@code doFilter}相同的合同,但保证在单个请求线程中每个请求只调用一次。
* /
protected abstract void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException;
}
参考网站: https://blog.csdn.net/ktlifeng/article/details/50630934
// GenericFilterBean.class
//使这个过滤器的名称对子类可用。类似于GenericServlet的{@code getServletName()}。<p>默认使用FilterConfig的过滤器名称。
//如果在Spring应用程序上下文中初始化为bean,那么它将返回到bean工厂中定义的bean名称。
@Nullable
protected String getFilterName() {
return (this.filterConfig != null ? this.filterConfig.getFilterName() : this.beanName);
}
更多推荐
已为社区贡献1条内容
所有评论(0)