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 { PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment)); initBeanWrapper(bw); 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. initFilterBean(); if (logger.isDebugEnabled()) { logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully"); } }
該方法來自於javax.servlet.Filter,即過濾器的初始化,它的主要工做集中於如下幾行代碼:
// 從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); // 初始化bean initFilterBean();
其中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的某部分功能,固然,具體如何執行由它們的子類規定,若你須要實現本身的過濾器,也能夠根據上文所述繼承你所須要的類。