Spring web過濾器-各類filter講解

      Spring的web包中中有不少過濾器,這些過濾器位於org.springframework.web.filter而且理所固然地實現了javax.servlet.Filter,不過實現的方式有如下幾類:java

        (1) 直接實現Filter,這一類過濾器只有CompositeFilter;web

        (2) 繼承抽象類GenericFilterBean,該類實現了javax.servlet.Filter,這一類的過濾器只有一個,即DelegatingFilterProxy;spring

        (3) 繼承抽象類OncePerRequestFilter,該類爲GenericFilterBean的直接子類,這一類過濾器包括CharacterEncodingFilter、HiddenHttpMethodFilter、HttpPutFormContentFilter、RequestContextFilter和ShallowEtagHeaderFilter;app

        (4) 繼承抽象類AbstractRequestLoggingFilter,該類爲OncePerRequestFilter的直接子類,這一類過濾器包括CommonsRequestLoggingFilter、Log4jNestedDiagnosticContextFilter和ServletContextRequestLoggingFilter。ide

        本文要講述的,便是GenericFilterBean、OncePerRequestFilter和AbstractRequestLoggingFilter。ui

        GenericFilterBeanthis

        抽象類GenericFilterBean實現了javax.servlet.Filter、org.springframework.beans.factory.BeanNameAware、org.springframework.context.EnvironmentAware、org.springframework.web.context.ServletContextAware、org.springframework.beans.factory.InitializingBean和org.springframework.beans.factory.DisposableBean五個接口,做用以下:debug

        (1) Filter,實現過濾器;日誌

        (2) BeanNameAware,實現該接口的setBeanName方法,便於Bean管理器生成Bean;code

        (3) EnvironmentAware,實現該接口的setEnvironment方法,指明該Bean運行的環境;

        (4) ServletContextAware,實現該接口的setServletContextAware方法,指明上下文;

        (5) InitializingBean,實現該接口的afterPropertiesSet方法,指明設置屬性生的操做;

        (6) DisposableBean,實現該接口的destroy方法,用於回收資源。

        GenericFilterBean的工做流程是:init-doFilter-destory,其中的init和destory在該類中實現,doFilter在具體實現類中實現。init的代碼以下:

/**
	 * Standard way of initializing this filter.
	 * Map config parameters onto bean properties of this filter, and
	 * invoke subclass initialization.
	 * @param filterConfig the configuration for this filter
	 * @throws ServletException if bean properties are invalid (or required
	 * properties are missing), or if subclass initialization fails.
	 * @see #initFilterBean
	 */
	public final void init(FilterConfig filterConfig) throws ServletException {
		Assert.notNull(filterConfig, "FilterConfig must not be null");
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing filter '" + filterConfig.getFilterName() + "'");
		}
 
		this.filterConfig = filterConfig;
 
		// Set bean properties from init parameters.
		try {
            // 從properties文件中獲取值,這裏是web.xml
			PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);
            // 設置bean適配器
			BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            // 設置上下文,這裏的servletContext的設定繼承自ServletContextAware的setter
			ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());
            // 將上下文信息和環境信息設置到bean適配器中,這裏的environment來自於EnvironmentAware的setter
			bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));
            // 初始化bean適配器
			initBeanWrapper(bw);
            // 將從properties中獲取的資源放置到bean適配器
			bw.setPropertyValues(pvs, true);
		}
		catch (BeansException ex) {
			String msg = "Failed to set bean properties on filter '" +
			    filterConfig.getFilterName() + "': " + ex.getMessage();
			logger.error(msg, ex);
			throw new NestedServletException(msg, ex);
		}
 
		// Let subclasses do whatever initialization they like.
        // 初始化bean
		initFilterBean();
 
		if (logger.isDebugEnabled()) {
			logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully");
		}
	}

       其中initFilterBean方法在兩個位置起做用,一處是上文所述的init方法,另外一處是afterPropertiesSet方法,在調用該方法前,須要保證用於Filter的全部的bean都已被設置,該方法由子類實現。

        GenericFilterBean中包含一個內部私有類FilterConfigPropertyValues,主要用於將web.xml中定義的init-param的值取出。

        OncePerRequestFilter

        抽象類oncePerRequestFilter繼承自GenericFilterBean,它保留了GenericFilterBean中的全部方法並對之進行了擴展,在oncePerRequestFilter中的主要方法是doFilter,代碼以下:
 

/**
	 * This <code>doFilter</code> implementation stores a request attribute for
	 * "already filtered", proceeding without filtering again if the
	 * attribute is already there.
	 * @see #getAlreadyFilteredAttributeName
	 * @see #shouldNotFilter
	 * @see #doFilterInternal
	 */
	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;
                // 調用GenericFilterBean的getFilterName方法返回已過濾的屬性名
		String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
		if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {
			// 未調用該過濾器或已過濾
			filterChain.doFilter(request, response);
		}
		else {
			// 進行過濾
			request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
			try {
				doFilterInternal(httpRequest, httpResponse, filterChain);
			}
			finally {
				// Remove the "already filtered" request attribute for this request.
				request.removeAttribute(alreadyFilteredAttributeName);
			}
		}
	}

       在doFilter方法中,doFilterInternal方法由子類實現,主要做用是規定過濾的具體方法。

AbstractRequestLoggingFilter

        AbstractRequestLoggingFilter繼承了OncePerRequestFilter並實現了其doFilterInternal方法,該方法代碼以下:

/**
	 * Forwards the request to the next filter in the chain and delegates down to the subclasses to perform the actual
	 * request logging both before and after the request is processed.
	 *
	 * @see #beforeRequest
	 * @see #afterRequest
	 */
	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		if (isIncludePayload()) {
                        // 若日誌中包含負載,則重置request
			request = new RequestCachingRequestWrapper(request);
		}
                // 過濾前執行的方法
		beforeRequest(request, getBeforeMessage(request));
		try {
                        // 執行過濾
			filterChain.doFilter(request, response);
		}
		finally {
                        // 過濾後執行的方法
			afterRequest(request, getAfterMessage(request));
		}
	}

      doFilter方法中的beforeRequest和afterRequest方法由子類實現,RequestCachingRequestWrapper爲AbstractRequestLoggingFilter的內部內,主要做用是重置request。
        區別

         咱們在使用過濾器時,一般不必知道GenericFilterBean、OncePerRequestFilter和AbstractRequestLoggingFilter,但不防礙咱們瞭解這幾個類,就上文所述,AbstractRequestLoggingFilter繼承自OncePerRequestFilter,OncePerRequestFilter繼承自GenericFilterBean,因此咱們知道,genericFilterBean是任何類型的過濾器的一個比較方便的超類,這個類主要實現的就是從web.xml文件中取得init-param中設定的值,而後對Filter進行初始化(固然,其子類能夠覆蓋init方法)。

         OncePerRequestFilter繼承自GenericFilterBean,那麼它天然知道怎麼去獲取配置文件中的屬性及其值,因此其重點不在於取值,而在於確保在接收到一個request後,每一個filter只執行一次,它的子類只須要關注Filter的具體實現即doFilterInternal。

        AbstractRequestLoggingFilter是對OncePerRequestFilter的擴展,它除了遺傳了其父類及祖先類的全部功能外,還在doFilterInternal中決定了在過濾以前和以後執行的事件,它的子類關注的是beforeRequest和afterRequest。

        整體來講,這三個類分別執行了Filter的某部分功能,固然,具體如何執行由它們的子類規定,若你須要實現本身的過濾器,也能夠根據上文所述繼承你所須要的類。  

相關文章
相關標籤/搜索