DelegatingFilterProxy是一個標准servlet Filter的代理,代理實現了Filter接口的spring管理的Bean。支持一個在web.xml的init-param定義的"targetBeanName" filter,在spring applicationContext中指定了target bean的名稱。
web.xml通常包含一個DelegatingFilterProxy的定義,它在root springContext中指定了filter-name及對應的bean。在springcontext中實現了標准servlet filter接口的bean在調用時都將被代理。
注意:Servlet Filter接口默認定義的lifecycle方法不會被代理到target bean,它依賴spring applicationContext管理target bean的lifecycle。在filter的屬性targetFilterLifecycle的init-param中指定為true將強制執行Filter.init()和Filter.destory()方法,讓Filter來管理filter的lifecycle。
從spring 3.1開始,DelegatingFilterProxy更新到可以支持servlet 3.0基於實例的filter注冊方法來構建,通常和spring 3.1的 org.springframework.web.WebApplicationInitializer spi一起使用。這個類由spring security中Ben Alex 寫的FilterToBeanProxy靈感觸發而寫的。
具體實現如下:
1.初始化方法
@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) { 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); } } } }
初始化代理
/** * Initialize the Filter delegate, defined as bean the given Spring * application context. * <p>The default implementation fetches the bean from the application context * and calls the standard {@code Filter.init} method on it, passing * in the FilterConfig of this Filter proxy. * @param wac the root application context * @return the initialized delegate Filter * @throws ServletException if thrown by the Filter * @see #getTargetBeanName() * @see #isTargetFilterLifecycle() * @see #getFilterConfig() * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) */ protected Filter initDelegate(WebApplicationContext wac) throws ServletException { Filter delegate = wac.getBean(getTargetBeanName(), Filter.class); if (isTargetFilterLifecycle()) { delegate.init(getFilterConfig()); } return delegate; }
2. 觸發代理方法
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { // Lazily initialize the delegate if necessary. 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 or DispatcherServlet registered?"); } this.delegate = initDelegate(wac); } delegateToUse = this.delegate; } } // Let the delegate perform the actual doFilter operation. invokeDelegate(delegateToUse, request, response, filterChain); }
觸發代理
/** * Actually invoke the delegate Filter with the given request and response. * @param delegate the delegate Filter * @param request the current HTTP request * @param response the current HTTP response * @param filterChain the current FilterChain * @throws ServletException if thrown by the Filter * @throws IOException if thrown by the Filter */ protected void invokeDelegate( Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { delegate.doFilter(request, response, filterChain); }
3.銷毀方法
/** * Destroy the Filter delegate. * Default implementation simply calls {@code Filter.destroy} on it. * @param delegate the Filter delegate (never {@code null}) * @see #isTargetFilterLifecycle() * @see javax.servlet.Filter#destroy() */ protected void destroyDelegate(Filter delegate) { if (isTargetFilterLifecycle()) { delegate.destroy(); } }