DelegatingFilterProxy的作用與用法
阿新 • • 發佈:2019-04-07
一、類結構
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.Spri