DelegatingFilterProxy這個東西太熟悉了,在相似shiro和springsecurity的權限認證框架都有見到它的身影,但又陌生,印象彷佛只停留在DelegatingFilterProxy把servlet 容器中的filter同spring容器中的bean關聯起來,交由spring容器管理。DelegatingFilterProxy代理類把filter和IOC容器進行告終合在一塊兒,從spring上下文尋找要代理的過濾類,執行初始化,過濾和銷燬過程。下面結合springsecurity就翻翻源碼:java
DelegatingFilterProxy
繼承了GenericFilterBean
,父類實現了一堆接口:web
public abstract class GenericFilterBean implements Filter, BeanNameAware, EnvironmentAware, EnvironmentCapable, ServletContextAware, InitializingBean, DisposableBean 複製代碼
- BeanNameAware //返回當前的beanName
- EnvironmentAware//讀取配置文件
- EnvironmentCapable//檢查接受了BeanFactory接口的框架方法
- ServletContextAware//獲取ServletContext
- InitializingBean//初始化bean對象
- DisposableBean //銷燬bean
父類中init
方法將過濾器的參數配置傳遞給代理對象 源碼以下:spring
public final void init(FilterConfig filterConfig) throws ServletException {
Assert.notNull(filterConfig, "FilterConfig must not be null");
this.filterConfig = filterConfig;
PropertyValues pvs = new GenericFilterBean.FilterConfigPropertyValues(filterConfig, this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());
Environment env = this.environment;
if (env == null) {
env = new StandardServletEnvironment();
}
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, (PropertyResolver)env));
this.initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
} catch (BeansException var6) {
String msg = "Failed to set bean properties on filter '" + filterConfig.getFilterName() + "': " + var6.getMessage();
this.logger.error(msg, var6);
throw new NestedServletException(msg, var6);
}
}
複製代碼
獲取目標對象的name。app
protected void initFilterBean() throws ServletException {
synchronized(this.delegateMonitor) {
if (this.delegate == null) {
if (this.targetBeanName == null) {
this.targetBeanName = this.getFilterName();
}
WebApplicationContext wac = this.findWebApplicationContext();
if (wac != null) {
this.delegate = this.initDelegate(wac);
}
}
}
}
複製代碼
在web.xml文件中配置的org.springframework.web.context.ContextLoaderListener
實現加載Sping的上下文環境 (由XmlWebApplicationContent來裝載)。 經過initDelegate(wac)獲得代理過濾器框架
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
String targetBeanName = this.getTargetBeanName();
Assert.state(targetBeanName != null, "No target bean name set");
Filter delegate = (Filter)wac.getBean(targetBeanName, Filter.class);
if (this.isTargetFilterLifecycle()) {
delegate.init(this.getFilterConfig());
}
return delegate;
}
複製代碼
在執行過濾方法以前,經過invokeDelegate
調用delegate執行過濾方法ui
protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
delegate.doFilter(request, response, filterChain);
}
複製代碼
過濾方法this
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
Filter delegateToUse = this.delegate;
if (delegateToUse == null) {
synchronized(this.delegateMonitor) {
delegateToUse = this.delegate;
if (delegateToUse == null) {
WebApplicationContext wac = this.findWebApplicationContext();
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener or DispatcherServlet registered?");
}
delegateToUse = this.initDelegate(wac);
}
this.delegate = delegateToUse;
}
}
複製代碼
protected void destroyDelegate(Filter delegate) {
if (this.isTargetFilterLifecycle()) {
delegate.destroy();
}
}
複製代碼
shiro的代理過濾器大體相似。spa