DelegatingFilterProxy作用浅析

今天看别人的代码,在web.xml文件部署描述符中配置了一个这样的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>/xx/*</url-pattern>
</filter-mapping>
同时在使用springSecurity的时候,也会使用类似的配置:

<filter>
   <filter-name>springSecurityFilterChain</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>springSecurityFilterChain</filter-name>
   <url-pattern>/xx/*</url-pattern>
</filter-mapping>
 个人觉得,spring-web 炸包下面的这个代理类 主要作用如下:

使filter可以使用spring中的bean,达到可插拔的效果。比如你可以使用shiro或者springSecurity等安全框架来进行权限管理,这样也算是使安全验证这一块与spring解耦。

 具体过程:web.xml中的ContextLoaderListener会将spring及你使用的shiro或者springSecurity的相关配置文件加载,然后初始化声明的bean,这其中就有filter中要用到的bean;这样filter用到这些bean的时候就可以到spring的bean容器中去取了。

DelegatingFilterProxy的继承关系如下:


而GenericFilterBean实现了如下接口:

public abstract class GenericFilterBean implements
      Filter, BeanNameAware, EnvironmentAware, ServletContextAware, InitializingBean, DisposableBean {...}
DelegatingFilterProxy类extends抽象类GenericFilterBean,implements接口Filter,Servlet容器在启动时,首先会调用Filter的init方法,init()方法继承自GenericFilterBean类,主要作用是把Filter的初始化参数set到继承于GenericFilterBean类的Filter中,同时调用了留给subClass实现的initFilterBean()方法来从spring的上下文环境中拿你想适配的bean,这是就是shiro的bean。

@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 {
      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");
   }
}

/**
 * Subclasses may override this to perform custom initialization.
 * All bean properties of this filter will have been set before this
 * method is invoked.
 * <p>Note: This method will be called from standard filter initialization
 * as well as filter bean initialization in a Spring application context.
 * Filter name and ServletContext will be available in both cases.
 * <p>This default implementation is empty.
 * @throws ServletException if subclass initialization fails
 * @see #getFilterName()
 * @see #getServletContext()
 */
protected void initFilterBean() throws ServletException {
}

下面贴一下DelegatingFilterProxy的initFilterBean()实现:

@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) {
            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) {
            this.delegate = initDelegate(wac);
         }
      }
   }
}//DelegatingFilterProxy重写了该方法,实现的作用是根据你配置的filter名字去Spring上下文中捞取你引入的filterBean
,设置到此类的this.delegate属性中,以待之后来了请求委托调用。

我们都知道一个filter的主要方法是doFilter(...),让我们来看 一下DelegatingFilterProxy类的这个方法:

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

   // Lazily initialize the delegate if necessary.
   Filter delegateToUse = this.delegate;
   if (delegateToUse == null) {
      synchronized (this.delegateMonitor) {
         if (this.delegate == null) {
            WebApplicationContext wac = findWebApplicationContext();//获取spring上下文
            if (wac == null) {
               throw new IllegalStateException("No WebApplicationContext found: " +
                     "no ContextLoaderListener or DispatcherServlet registered?");
            }
            this.delegate = initDelegate(wac);//初始化delegate,也即最终你引入的安全框架的filterBean
         }
         delegateToUse = this.delegate;
      }
   }

   // Let the delegate perform the actual doFilter operation.
   invokeDelegate(delegateToUse, request, response, filterChain);//最终调用实际你引入的filter的doFilter()方法
}
在设置shiroFilter时候有一个属性叫targetFilterLifecycle,默认为false。此属性的作用是:是否启用引入filter的init()和destry()方法。代码如下:

/**
 * Initialize the Filter delegate, defined as bean the given Spring
 * application context.
 * <p>The default implementation fetches the bean from the application context
 * and calls the standard {@code Filter.init} method on it, passing
 * in the FilterConfig of this Filter proxy.
 * @param wac the root application context
 * @return the initialized delegate Filter
 * @throws ServletException if thrown by the Filter
 * @see #getTargetBeanName()
 * @see #isTargetFilterLifecycle()
 * @see #getFilterConfig()
 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
 */
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
   Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
   if (isTargetFilterLifecycle()) {//如果为true,则调用引入的filter的初始化方法,即shiroFilter的init()方法
      delegate.init(getFilterConfig());
   }
   return delegate;
}
时间有限,写的有点乱。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值