Spring MVC過濾器-超類 GenericFilterBean

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的某部分功能,固然,具體如何執行由它們的子類規定,若你須要實現本身的過濾器,也能夠根據上文所述繼承你所須要的類。

相關文章
相關標籤/搜索