DelegatingFilterProxy的作用與用法


一、類結構

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

二、代理具體實現

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

/**
 * 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中去看看,具體完成了那些工作?
  //1、找到要代理bean的id--》targetBeanName
  //2、在spring,bean容器中找到具體被代理的filter--》delegate
initFilterBean(); if (logger.isDebugEnabled()) { logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully"); } }

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

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

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

@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中配置的id

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

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

//找到被代理的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是如何運用這個類的

三、運用
  首先我們看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"/>
 
        
  第一次寫博客,存在很多不足,希望大家見諒。
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM