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的某部分功能,固然,具体如何执行由它们的子类规定,若你须要实现本身的过滤器,也能够根据上文所述继承你所须要的类。  

相关文章
相关标签/搜索