DelegatingFilterProxy類的做用

 

DelegatingFilterProxy類的一些內部運行機制,其實主要做用就是一個代理模式的應用,能夠把servlet 容器中的filter同spring容器中的bean關聯起來。樓主說這樣能夠可拔插的效果。是能夠像處理bean同樣銷燬。

html

使用過springSecurity的朋友都知道,首先須要在web.xml進行如下配置java

<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> <!-- 默認是false -->
 
</init-param>
 
</filter>
 
 
 
<filter-mapping>
 
<filter-name>springSecurityFilterChain</filter-name>
 
<url-pattern>/*</url-pattern>
 
</filter-mapping>

 

非springSecurity用法以下:web

<filter>
 
<filter-name>DelegatingFilterProxy</filter-name>
 
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 
<init-param>
 
<param-name>targetBeanName</param-name>
 
<!-- 自定義filter -->
 
<param-value>exportExamineFilter</param-value>
 
</init-param>
 
<init-param>
 
<!-- 判斷targetFilterLifecycle屬性是false仍是true,決定是否調用自定義類的init()、destry()方法 -->
 
<param-name>targetFilterLifecycle</param-name>
 
<param-value>false</param-value>
 
</init-param>
 
</filter>
 
<filter-mapping>
 
<filter-name>DelegatingFilterProxy</filter-name>
 
<url-pattern>/*</url-pattern>
 
</filter-mapping>

 

 

從這個配置中,可能會給咱們形成一個錯覺,覺得DelegatingFilterProxy類就是springSecurity的入口,但其實這個類位於spring-web-3.0.5.RELEASE.jar這個jar下面,說明這個類自己是和springSecurity無關。DelegatingFilterProxy類繼承於抽象類GenericFilterBean,間接地implement 了javax.servlet.Filter接口,Servlet容器在啓動時,首先會調用Filter的init方法,GenericFilterBean的做用主要是能夠把Filter的初始化參數自動地set到繼承於GenericFilterBean類的Filter中去。在其init方法的以下代碼就是作了這個事: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));
 
initBeanWrapper(bw);
 
bw.setPropertyValues(pvs, true);

 

另外在init方法中調用了initFilterBean()方法,該方法是GenericFilterBean類是特意留給子類擴展用的安全

protected void initFilterBean() throws ServletException {
 
// 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.
 
synchronized (this.delegateMonitor) {
 
WebApplicationContext wac = findWebApplicationContext();
 
if (wac != null) {
 
this.delegate = initDelegate(wac);
 
}
 
}
 
}

 

能夠看出上述代碼首先看Filter是否提供了targetBeanName初始化參數,若是沒有提供則直接使用filter的name作爲beanName,產生了beanName後,因爲咱們在web.xml的filter的name是springSecurityFilterChain,從spring的IOC容器中取出bean的代碼是initDelegate方法,下面是該方法代碼:app

protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
 
Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
 
if (isTargetFilterLifecycle()) {
 
delegate.init(getFilterConfig());
 
}
 
return delegate;
 
}

經過跟蹤代碼,發現取出的bean是org.springframework.security.FilterChainProxy,該類也是繼承於GenericFilterBean,取出bean後,判斷targetFilterLifecycle屬性是false仍是true,決定是否調用該類的init方法。這個FilterChainProxy bean實例最終被保存在DelegatingFilterProxy類的delegate屬性裏,

下面看一下DelegatingFilterProxy類的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(delegateToUse, request, response, filterChain);這句代碼,在下面能夠看出DelegatingFilterProxy類實際是用其delegate屬性即org.springframework.security.FilterChainProxy實例的doFilter方法來響應請求。ui

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

 

以上就是DelegatingFilterProxy類的一些內部運行機制,其實主要做用就是一個代理模式的應用,能夠把servlet 容器中的filter同spring容器中的bean關聯起來。

此外還要注意一個DelegatingFilterProxy的一個初始化參數:targetFilterLifecycle ,其默認值爲false 。 但若是被其代理的filter的init()方法和destry()方法須要被調用時,須要設置targetFilterLifecycle爲true。具體可見DelegatingFilterProxy中的以下代碼:this

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);
 
}
 
}
 
}
 
}
 
 
 
 
 
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
 
Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
 
if (isTargetFilterLifecycle()) { //注意這行
 
delegate.init(getFilterConfig());
 
}
 
return delegate;
 
}

轉載地址:http://www.cnblogs.com/hzhuxin/archive/2011/12/19/2293730.htmlurl

 

轉載有用的評論以下:

 

#4樓   2015-03-19 14:33 讓本身行動起來  
我以爲Spring如此費功能的設計兩個Filter,一個代理的Filter,還有一個真實的Security Filter主要是爲了讓Spring MVC可插拔性,也就是說你的security框架能夠不用Spring的,能夠用其它任何一家的security框架。
這也是爲何org.springframework.web.filter.DelegatingFilterProxy這個類是位於spring-web這個jar包下面。
我研究了一下,其過程是這樣的。
web.xml下面我們會配一個listen-class爲org.springframework.web.context.ContextLoaderListener,而後其對應的contextConfigLocation Spring會把spring context及spring security的XML配置文件裝載入Spring Bean容器中(由XmlWebApplicationContent來裝載),而後在兄臺上面說的
Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
這個方法的時候,Delegate就會向Spring容器要實現了Filter的叫targetBeanName的值(你上面配的是springSecurityFilterChain)的類,若是咱們contextConfigLocation配置了Spring security的配置文件,天然就有這個springSecurityFilterChain的Bean了。若是咱們不想用Spring Security,那麼也能夠在此處替換成咱們要的security實現類。

不過我卻是沒有搞明白爲何org.springframework.security.web.FilterChainProxy在Spring容器中的BeanName爲何是叫springSecurityFilterChain?
  
#5樓 [ 樓主] 2015-07-10 19:10 杭州胡欣  
@ 讓本身行動起來
這是springSecurity在加載自身的配置文件時指定的,只不過這個加載過程隱藏在命名空間之下了,也就是說BeanName的命名人家已經隱式地指定了,因此你看不到,人家就在文檔上告訴你了。DelegatingFilterProxy類的真實做用就是爲了讓你在filter的配置上能引用spring的bean,這樣達到可插拔的效果。
 
#9樓   2016-09-23 15:57 akka_li  
「DelegatingFilterProxy類的一些內部運行機制,其實主要做用就是一個代理模式的應用,能夠把servlet 容器中的filter同spring容器中的bean關聯起來」我以爲樓主說得這句是最重要的!

spring security爲何要用filter實現,而非aop、interceptor等等,?這些組件都是在dispatcherServlet以後執行的,此時再作一些安全校驗是否是太晚(本身瞎猜的,主要是助於本身理解,在此作個筆記,有錯但願指出!!!)

而肯定了filter實現spring security,那麼爲何又整出來一個DelegatingFilterProxy代理類啊? 若是沒有這個代理類,那麼你就須要把spring security框架中的filter都配置到web.xml中,這樣的用戶體驗過太差了,並且耦合得太緊密了;同時你經過web.xml配置這些filter,而沒有經過spring ioc容器進行管理,有點不符合總體思想!而filter是屬於java web的東西,必須配置在web.xml中,因此就有了目前的機制,經過配置一個DelegatingFilterProxy類到web.xml中,其餘的spring security中的filter配置到ioc容器中管理,經過DelegatingFilterProxy代理類把javaweb中的filter和spring ioc容器中的filter關聯起來了!(是本身目前的一種理解,若是有錯,但願你們指出來,謝謝)

 

https://blog.csdn.net/romantic_pk/article/details/53082201

相關文章
相關標籤/搜索