Spring Servlet Web 5.1.3 常用过滤器 : RequestContextFilter

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/andy_zhang2007/article/details/86084499

概述

该过滤器将当前请求暴露到当前线程,具体是通过org.springframework.context.i18n.LocaleContextHolderRequestContextHolder。这样当前请求随后的处理过程中,就可以在当前线程中获取的当前请求的信息,而无需把请求对象作为参数到处传递 。

这里注意一个概念,缺省情况下,Servlet容器对一个请求的整个处理过程,是由同一个线程完成的,中途不会切换线程。但这个线程在处理完一个请求后,会被放回到线程池用于处理其他请求。

该过滤器由web.xml或者WebMvcAutoConfiguration注册。

Springorg.springframework.web.context.request.RequestContextListenerorg.springframework.web.servlet.DispatcherServlet也做了同样的工作:将当前请求暴露到当前线程。该过滤器RequestContextFilter主要是用于第三方serlvet比如JSF FacesServlet。在Spring自己的Web应用中,如果一个请求最终被DispatcherServlet处理,起始DispatcherServlet中往当前线程中设置请求的逻辑已经已经足够了,但是在一个Web应用中,并不是所有的请求都最终会被DispatcherServlet处理,比如匿名用户访问一个登录用户才能访问的资源,此时请求只会被安全过滤器处理,而不会到达DispatcherServlet,在这种情况下,该过滤器RequestContextFilter就起了担当了相应的职责。

该过滤器继承自OncePerRequestFilter,也就是说,它在整个请求处理过程中最多只会被应用一次。

Springboot 提供了一个OrderedRequestContextFilter继承自RequestContextFilter应用在基于SpringbootServlet Web应用中。OrderedRequestContextFilterRequestContextFilter的功能上增加了接口OrderedFilter定义的过滤器顺序,并且缺省使用优先级(-105)。在整个Servlet过滤器链中,过滤器的顺序数字越小,表示越先被调用。

源代码分析

package org.springframework.web.filter;

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


public class RequestContextFilter extends OncePerRequestFilter {

    // 是否向子线程传播 LocaleContext 和 RequestAttributes,缺省为false,不传播
	private boolean threadContextInheritable = false;


	// 设置是否向子线程传播 LocaleContext 和 RequestAttributes
	public void setThreadContextInheritable(boolean threadContextInheritable) {
		this.threadContextInheritable = threadContextInheritable;
	}


	// 返回 false, 表示对异步派发线程也建立request context
	@Override
	protected boolean shouldNotFilterAsyncDispatch() {
		return false;
	}

	// 返回 false, 表示对error派发也建立request context
	@Override
	protected boolean shouldNotFilterErrorDispatch() {
		return false;
	}

	@Override
	protected void doFilterInternal(
			HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

       // 封装当前请求/响应对象到一个 ServletRequestAttributes
		ServletRequestAttributes attributes = new ServletRequestAttributes(request, response);
       // 将封装了的 ServletRequestAttributes 对象 attributes,当前请求的 locale 分别记录到对应当前线程的
       // RequestContextHolder 和 LocaleContextHolder
		initContextHolders(request, attributes);

        // 上面的逻辑为当前请求的处理在当前线程中做了locale和请求/响应对象的记录,下面继续执行
        // 过滤器链
		try {
			filterChain.doFilter(request, response);
		}
		finally {
           // 请求处理完成,再次返回到该过滤器,此时要清除当前线程中记录的locale和请求/响应对象
           // 信息,因为当前线程可能被放回线程池供处理其他请求使用
			resetContextHolders();
			if (logger.isTraceEnabled()) {
				logger.trace("Cleared thread-bound request context: " + request);
			}
			attributes.requestCompleted();
		}
	}

    // 将封装了的 ServletRequestAttributes 对象 attributes,当前请求的 locale 分别记录到对应当前线程的
    // RequestContextHolder 和 LocaleContextHolder
	private void initContextHolders(HttpServletRequest request, ServletRequestAttributes requestAttributes) {
		LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable);
		RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
		if (logger.isTraceEnabled()) {
			logger.trace("Bound request context to thread: " + request);
		}
	}

    // 清除当前线程中记录的locale和请求/响应对象
	private void resetContextHolders() {        
		LocaleContextHolder.resetLocaleContext();
		RequestContextHolder.resetRequestAttributes();
	}

}

猜你喜欢

转载自blog.csdn.net/andy_zhang2007/article/details/86084499