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
轉載有用的評論以下:
https://blog.csdn.net/romantic_pk/article/details/53082201
這也是爲何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?