1、類結構web
DelegatingFilterProxy類存在與spring-web包中,其做用就是一個filter的代理,用這個類的好處是能夠經過spring容器來管理filter的生命週期,還有就是,能夠經過spring注入的形式,來代理一個filter執行,如shiro,下面會說到;有上圖咱們能夠看到,DelegatingFilterProxy類繼承GenericFilterBean,間接實現了Filter這個接口,故而該類屬於一個過濾器。那麼就會有實現Filter中init、doFilter、destroy三個方法。spring
2、代理具體實現app
首先咱們看init方法,咱們知道當filter初始化時會執行init方法,從源碼中咱們能夠找到具體代碼,該方法在GenericFilterBean類中實現,具體功能是,將該類封裝成spring特有形式的類,方便spring維護,而且調用initFilterBean方法,該方法放在子類(DelegatingFilterProxy)實現,該方法主要目的是,找到在spring中維護的目標filter,具體實現看下面代碼:ide
/** * 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中去看看,具體完成了那些工做? //一、找到要代理bean的id--》targetBeanName //二、在spring,bean容器中找到具體被代理的filter--》delegate initFilterBean(); if (logger.isDebugEnabled()) { logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully"); } }
initFilterBean()該方法主要完成兩個功能:ui
一、找到被代理類在spring中配置的id並賦值給targetBeanName。this
二、使用找到的id從spring容器中找到具體被代理的類,並賦值給delegateurl
@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中配置的idspa
protected final String getFilterName() { //找到被代理filter在spring中配置的id return (this.filterConfig != null ? this.filterConfig.getFilterName() : this.beanName); }
initDelegate()該方法的做用是,從spring容器中獲取到具體被代理的filter debug
//找到被代理的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是如何運用這個類的 3、運用 首先咱們看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.SpringShiroFilter"/>