转自: http://blog.csdn.net/ktlifeng/article/details/50630934
基于4.1.7.RELEASE
我们先看一个filter-mapping的配置
- <filter-mapping>
- <filter-name>encodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- <dispatcher>REQUEST</dispatcher>
- <dispatcher>ASYNC</dispatcher>
- </filter-mapping>
这里指定了一个ASYNC的配置,表明过滤异步请求,这个ASYNC即是枚举类DispatcherType中的一个元素,在Servlet3.0中,如果一个请求是DispatcherType.ASYNC类型的,那么在一个单一请求的过程中,filter能够被多个线程调用,也就是意味着一个filter可能在一次请求中被多次执行,这显然是会有问题的,那么spring是怎么避免这个问题的呢?这就是今天要说的OncePerRequestFilter。
直接看doFilter方法
- @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)) {
- // 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);
- }
- }
- }
从源码可以看出,spring会给已经过滤过的request设置一个attribute,在filter链和目标方法执行完毕之后才会释放这个attribute,attribute的名字是从 getAlreadyFilteredAttributeName() 方法得来,默认为filter的名字加后缀,如果filter没有完全初始化,则改为类名加后缀,后缀为“.FILTERED”
- protected String getAlreadyFilteredAttributeName() {
- String name = getFilterName();
- if (name == null) {
- name = getClass().getName();
- }
- return name + ALREADY_FILTERED_SUFFIX;
- }
获取完名字之后,需要进行判断是否已经执行过这个filter了,判断条件有3个
1 是否有hasAlreadyFilteredAttribute
2 是否skipDispatch
3 是否不进行过滤
我们直接看2和3,步骤3里,根据shouldNotFilter(httpRequest)来判断是否进行过滤,其实现依赖于子类。
在2里面判断条件有两种
- 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;
- }
1 是异步并且不应该过滤异步,则skipDispatch为true,即不进行过滤
2 是ERROR请求并且不应该过滤ERROR,同样返回true
在上述所有判断条件完成之后,就可以决定是否执行
- doFilterInternal(httpRequest, httpResponse, filterChain);
方法了,这个方法就是子类具体实现的方法,其中之一便是前一篇文章中讲的CharacterEncodingFilter。
还需要注意的一个方法是
- protected boolean isAsyncStarted(HttpServletRequest request) {
- return WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted();
- }
如果这个返回true,那么当前线程结束时不会将response提交回去。
- 顶
- 1
转自: http://blog.csdn.net/ktlifeng/article/details/50630934
基于4.1.7.RELEASE
我们先看一个filter-mapping的配置
- <filter-mapping>
- <filter-name>encodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- <dispatcher>REQUEST</dispatcher>
- <dispatcher>ASYNC</dispatcher>
- </filter-mapping>
这里指定了一个ASYNC的配置,表明过滤异步请求,这个ASYNC即是枚举类DispatcherType中的一个元素,在Servlet3.0中,如果一个请求是DispatcherType.ASYNC类型的,那么在一个单一请求的过程中,filter能够被多个线程调用,也就是意味着一个filter可能在一次请求中被多次执行,这显然是会有问题的,那么spring是怎么避免这个问题的呢?这就是今天要说的OncePerRequestFilter。
直接看doFilter方法
- @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)) {
- // 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);
- }
- }
- }
从源码可以看出,spring会给已经过滤过的request设置一个attribute,在filter链和目标方法执行完毕之后才会释放这个attribute,attribute的名字是从 getAlreadyFilteredAttributeName() 方法得来,默认为filter的名字加后缀,如果filter没有完全初始化,则改为类名加后缀,后缀为“.FILTERED”
- protected String getAlreadyFilteredAttributeName() {
- String name = getFilterName();
- if (name == null) {
- name = getClass().getName();
- }
- return name + ALREADY_FILTERED_SUFFIX;
- }
获取完名字之后,需要进行判断是否已经执行过这个filter了,判断条件有3个
1 是否有hasAlreadyFilteredAttribute
2 是否skipDispatch
3 是否不进行过滤
我们直接看2和3,步骤3里,根据shouldNotFilter(httpRequest)来判断是否进行过滤,其实现依赖于子类。
在2里面判断条件有两种
- 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;
- }
1 是异步并且不应该过滤异步,则skipDispatch为true,即不进行过滤
2 是ERROR请求并且不应该过滤ERROR,同样返回true
在上述所有判断条件完成之后,就可以决定是否执行
- doFilterInternal(httpRequest, httpResponse, filterChain);
方法了,这个方法就是子类具体实现的方法,其中之一便是前一篇文章中讲的CharacterEncodingFilter。
还需要注意的一个方法是
- protected boolean isAsyncStarted(HttpServletRequest request) {
- return WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted();
- }
如果这个返回true,那么当前线程结束时不会将response提交回去。