DelegatingFilterProxy的使用
程序员文章站
2022-03-05 14:15:48
...
在Spring集成第三方时,通常会提供以下方式的配置来作为第三方引入的入口:
那么DelegatingFilterProxy是如何实现filter的代理?
获取Filter对象获取并执行init后,就需要关注doFilter,代码如下:
<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> <!-- 默认是false --> </init-param> </filter> <filter-mapping> < filter-name>shiroFilter</filter-name> < url-pattern>/*</url-pattern> </filter-mapping>从配置上来看,只是增加了一个filter,与引入的第三方框架没有什么关系。实际上DelegatingFilterProxy是org.springframework.web.filter中的一个特殊类,对于servlet filter进行代理,其好处在于可以通过spring容器来管理servlet filter对象及其生命周期。既然由spring容器进行管理,那和普通的bean就没有区别,也可以使用依赖注入机制、属性文件的操作等特性。
那么DelegatingFilterProxy是如何实现filter的代理?
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); } } } }从上述代码可以看出,如果没有提供初始化参数targetBeanName,就用filterName替代(必须与spring中定义的bean name对应),然后在spring IOC容器中获取该bean,下面看一下获取bean的代码initDelegate:
protected Filter initDelegate(WebApplicationContext wac) throws ServletException{ Filter delegate = wac.getBean(getTargetBeanName(), Filter.class); if (isTargetFilterLifecycle()) { delegate.init(getFilterConfig()); } return delegate; }从容器中获取bean对象,通过判断isTargetFilterLifecycle决定是否调用init(),默认为false。从代码中Filter.class看出,该类必须实现Filter接口。在Shiro对应的bean为ShiroFilterFactoryBean,该类是一个工厂类,并没有实现Filter接口,表面上看与上面的原则相违背。实际情况ShiroFilterFactoryBean是一个Filter工厂,其有一个内部类SpringShiroFilter,继承于AbstractShiroFilter,实现了Filter接口。getObject()、getObjectType()两个方法返回的也都是SpringShiroFilter类型,因此getBean实际返回的是SpringShiroFilter。Shiro源码分析可以参考:
引用
获取Filter对象获取并执行init后,就需要关注doFilter,代码如下:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { // Lazily initialize the delegate if necessary. Filter 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; } // Let the delegate perform the actual doFilter operation. invokeDelegate(delegateToUse, request, response, filterChain); }以上代码,需要重点关注invokeDelegate,Lazily initialize只有在init未调用delegate未初始化时执行。invokeDelegate代码:
protected void invokeDelegate( Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { delegate.doFilter(request, response, filterChain); }delegate为从spring容器中获取到的Filter,执行了doFilter方法。从上述代码可以看出DelegatingFilterProxy就是一个代理模式的应用,把servlet容器的filter与spring容器中bean有效的结合,综合了两者的特性。
上一篇: 过滤器浅谈
下一篇: Suricata 新建规则