Spring源码分析----DelegatingFilterProxy

 2019-11-02 21:20  阅读(1141)
文章分类:Spring boot

  本来是打算写shiro的过滤链是如何处理的,但是它是通过Spring的DelegatingFilterProxy来实现的,所以先得把DelegatingFilterProxy讲清楚。

顾名思义,DelegatingFilterProxy是一个代理类,代理我们标准的Filter类,并将其委托给一个实现了Filter接口的实例,不同之处在于这个实例是托管到spring中的。好处就很明显了,它可以享受到spring的便利之处,例如在filter类中注入其他的spring bean,更为复杂的初始化逻辑等等。

  既然是托管到了spring中,那么filter的生命周期就交给了spring来管理。但是filter是有自己的生命周期的,DelegatingFilterProxy通过一个名叫targetFilterLifecycle的属性指定是否需要完成filter自己的生命周期方法。

讲了这么多,先看看DelegatingFilterProxy的庐山真面目:

public class DelegatingFilterProxy extends GenericFilterBean {

        private String contextAttribute;

        private WebApplicationContext webApplicationContext;

        private String targetBeanName;

        private boolean targetFilterLifecycle = false;

        private volatile Filter delegate;

        private final Object delegateMonitor = new Object();

        // 省略了方法
    }

属性最重要的就是代理的Filter了,所有的过滤操作都由delegate来实现。webApplicationContext是spring mvc的上下文,delegate需要通过webApplicationContext来获取。targetFilterLifecycle是指明是否需要调用Filter自有的生命周期方法,默认是false。

  大家可以看到DelegatingFilterProxy继承了GenericFilterBean,对于GenericFilterBean,大家只需知道他实现了Filter接口就行了。

  接下来再看看DelegatingFilterProxy有哪些重要的方法:

@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);
                    }
                }
            }
        }

        @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);
        }

  首先是初始化代理的filterBean,如果定义filter的时候给出了targetBeanName,那么则通过webAppliction获取对应的bean,否则根据filterName去获取对应的bean。该方法会在filter的init方法调用时被调用,调用时机在GenericFilterBean里面。在doFilter的时候,则通过调用delegate的doFilter来实现,也就是上面的invokeDelegate()方法。

protected void invokeDelegate(
                Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {

            delegate.doFilter(request, response, filterChain);
        }

到这里就是很熟悉的Filter调用模式了。

之前说过,通过代理filter,delegate的生命周期就交给了spring来管理。但是filter是有自己的生命周期的,DelegatingFilterProxy通过一个名叫targetFilterLifecycle的属性指定是否需要完成filter自己的生命周期方法。在bean的创建和销毁时,判断是否需要调用filter的对应的方法。

@Override
        public void destroy() {
            Filter delegateToUse = this.delegate;
            if (delegateToUse != null) {
                destroyDelegate(delegateToUse);
            }
        }

附:代码示例

下载地址:https://download.csdn.net/download/gameloft9/10582213


来源:http://ddrv.cn

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Spring源码分析----DelegatingFilterProxy

相关推荐