代理過濾器

玉獅子發表於2019-04-22

DelegatingFilterProxy這個東西太熟悉了,在類似shiro和springsecurity的許可權認證框架都有見到它的身影,但又陌生,印象似乎只停留在DelegatingFilterProxy把servlet 容器中的filter同spring容器中的bean關聯起來,交由spring容器管理。DelegatingFilterProxy代理類把filter和IOC容器進行了結合在一起,從spring上下文尋找要代理的過濾類,執行初始化,過濾和銷燬過程。下面結合springsecurity就翻翻原始碼:

獲取filter配置引數

DelegatingFilterProxy繼承了GenericFilterBean ,父類實現了一堆介面:

public abstract class GenericFilterBean implements Filter, BeanNameAware, EnvironmentAware, EnvironmentCapable, ServletContextAware, InitializingBean, DisposableBean 
複製程式碼
  • BeanNameAware //返回當前的beanName
  • EnvironmentAware//讀取配置檔案
  • EnvironmentCapable//檢查接受了BeanFactory介面的框架方法
  • ServletContextAware//獲取ServletContext
  • InitializingBean//初始化bean物件
  • DisposableBean //銷燬bean

父類中init方法將過濾器的引數配置傳遞給代理物件 原始碼如下:

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);
            }
        }
複製程式碼

bean物件初始化

獲取目標物件的name。

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執行過濾方法

protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        delegate.doFilter(request, response, filterChain);
    }
複製程式碼

過濾方法

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的代理過濾器大致類似。

相關文章