DelegatingFilterProxy的做用與用法

1、類結構web

  DelegatingFilterProxy類存在與spring-web包中,其做用就是一個filter的代理,用這個類的好處是能夠經過spring容器來管理filter的生命週期,還有就是,能夠經過spring注入的形式,來代理一個filter執行,如shiro,下面會說到;有上圖咱們能夠看到,DelegatingFilterProxy類繼承GenericFilterBean,間接實現了Filter這個接口,故而該類屬於一個過濾器。那麼就會有實現Filter中init、doFilter、destroy三個方法。spring

2、代理具體實現app

  首先咱們看init方法,咱們知道當filter初始化時會執行init方法,從源碼中咱們能夠找到具體代碼,該方法在GenericFilterBean類中實現,具體功能是,將該類封裝成spring特有形式的類,方便spring維護,而且調用initFilterBean方法,該方法放在子類(DelegatingFilterProxy)實現,該方法主要目的是,找到在spring中維護的目標filter,具體實現看下面代碼:ide

複製代碼

/**
 * 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
 */
@Override
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 {
    //將該類封裝成spring特有的bean形式,方便spring維護
      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);
   }

   // 該方法在子類中實現,咱們能夠到DelegatingFilterPoxy中去看看,具體完成了那些工做?
  //一、找到要代理bean的id--》targetBeanName
  //二、在spring,bean容器中找到具體被代理的filter--》delegate

   initFilterBean();

   if (logger.isDebugEnabled()) {
      logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully");
   }
}

複製代碼

 initFilterBean()該方法主要完成兩個功能:ui

一、找到被代理類在spring中配置的id並賦值給targetBeanName。this

二、使用找到的id從spring容器中找到具體被代理的類,並賦值給delegateurl

複製代碼

@Override
protected void initFilterBean() throws ServletException {
   synchronized (this.delegateMonitor) {
      if (this.delegate == null) {
         // If no target bean name specified, use filter name.
         if (this.targetBeanName == null) {
       //找到要被代理的filter在spring中配置的id
            this.targetBeanName = getFilterName();
         }
         // Fetch Spring root application context and initialize the delegate early,
         // if possible. If the root application context will be started after this
         // filter proxy, we'll have to resort to lazy initialization.
         WebApplicationContext wac = findWebApplicationContext();
         if (wac != null) {
        //找到具體被代理的filter
            this.delegate = initDelegate(wac);
         }
      }
   }
}

複製代碼

getFilterName()該方法的做用是,獲取被代理的filter在spring中配置的idspa

protected final String getFilterName() {
  //找到被代理filter在spring中配置的id
   return (this.filterConfig != null ? this.filterConfig.getFilterName() : this.beanName);
}

initDelegate()該方法的做用是,從spring容器中獲取到具體被代理的filter debug

複製代碼

//找到被代理的filter
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
   Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
   if (isTargetFilterLifecycle()) {
      delegate.init(getFilterConfig());
   }
   return delegate;
}

複製代碼

到這裏咱們能夠看出來,咱們要代理的filter其實就是咱們配置filter中的filter-name標籤中的filterName了
<filter-name>filterName</filter-name>

咱們在來看看doFilter方法具體實現,該方法主要是使用被代理的filter,並調用invokeDelegate方法,
執行被代理filter的doFilter方法,具體實現,請看下面源碼:

複製代碼

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {

   // 獲得被代理的filter
   Filter delegateToUse = this.delegate;
   if (delegateToUse == null) {
      synchronized (this.delegateMonitor) {
         if (this.delegate == null) {
            WebApplicationContext wac = findWebApplicationContext();
            if (wac == null) {
               throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
            }
            this.delegate = initDelegate(wac);
         }
         delegateToUse = this.delegate;
      }
   }

   // 執行被代理filter的doFilter方法
   invokeDelegate(delegateToUse, request, response, filterChain);
}

複製代碼

invokeDelegate方法的做用就是執行被代理filter的doFilter方法

複製代碼

protected void invokeDelegate(
      Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {

   delegate.doFilter(request, response, filterChain);
}

複製代碼

看到這裏我相信你們都明白DelegatingFilterPoxy是怎麼回事了吧。下面咱們看看spring+shiro是如何運用這個類的

3、運用
  首先咱們看web.xml具體配置,注意<filter-name>中配置的name,以name爲id在spring的bean配置中找獲得對應的bean

複製代碼

<!-- Shiro Security filter-->
  <filter>
      <filter-name>shiroFilter</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
      <init-param>
          <param-name>targetFilterLifecycle</param-name>
          <param-value>true</param-value>
      </init-param>
  </filter>
  <filter-mapping>
      <filter-name>shiroFilter</filter-name>
      <url-pattern>/*</url-pattern>
      <dispatcher>REQUEST</dispatcher>
      <dispatcher>ERROR</dispatcher>
  </filter-mapping>

複製代碼

 spring對於代理filter配置
<bean id="shiroFilter" class="com.auth.SpringShiroFilter"/>
相關文章
相關標籤/搜索