zoukankan      html  css  js  c++  java
  • OncePerRequestFilter原理简介

    OncePerRequestFilter是Spring Boot里面的一个过滤器抽象类,其同样在Spring Security里面被广泛用到
    这个过滤器抽象类通常被用于继承实现并在每次请求时只执行一次过滤,这里面是如何实现的,我们可以通过源码找到答案

    public abstract class OncePerRequestFilter extends GenericFilterBean {
            //一个标记,后面会用到
    	public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";
    
    	@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;
    		//这里获取一个名称,该名称后面会被用于放到request当作key
    		String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
    		//检测当前请求是否已经拥有了该标记,如果拥有该标记则代表该过滤器执行过了(后面注释有说明)
    		boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;
    
    		if (skipDispatch(httpRequest) || shouldNotFilter(httpRequest)) {
    
    			// Proceed without invoking this filter...
    			filterChain.doFilter(request, response);
    		}
    		//如果此过滤器已经被执行过则执行如下的逻辑
    		else if (hasAlreadyFilteredAttribute) {
    
    			if (DispatcherType.ERROR.equals(request.getDispatcherType())) {
    				doFilterNestedErrorDispatch(httpRequest, httpResponse, filterChain);
    				return;
    			}
    
    			// Proceed without invoking this filter...
    			filterChain.doFilter(request, response);
    		}
    		//走到这里说明该过滤器没有被执行过
    		else {
    			// Do invoke this filter...
    			// 在当前请求里面设置一个标记,key就是前面拼接的那个变量,value是true,这个标记如果在request存在则在前面会被检测到并改变hasAlreadyFilteredAttribute的值
    			request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
    			try {
                                    // 这个方法是一个抽象方法需要子类去实现具体的过滤逻辑
    				doFilterInternal(httpRequest, httpResponse, filterChain);
    			}
    			finally {
    				// Remove the "already filtered" request attribute for this request.
    				// 执行完毕之后移除该标记
    				request.removeAttribute(alreadyFilteredAttributeName);
    			}
    		}
    	}
        //其余代码略
    }
    

    以上通过增加标记的方式来实现过滤器只被执行一次

  • 相关阅读:
    IOS小组件(8):App与Widget数据共享
    IOS小组件(7):小组件点击交互
    IOS小组件(6):小组件实现时钟按秒刷新
    IOS小组件(5):小组件刷新机制
    IOS小组件(4-2):创建可配置小组件(动态修改配置数据)
    IOS小组件(4-1):创建可配置小组件(静态配置数据)
    IOS小组件(3):SwiftUI开发小组件布局入门
    IOS小组件(2):小组件框架解析
    IOS小组件(1):概述
    python函数作用域
  • 原文地址:https://www.cnblogs.com/bcde/p/13787105.html
Copyright © 2011-2022 走看看