Spring源码分析----DelegatingFilterProxy

  本来是打算写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

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/GAMEloft9/article/details/81327492
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞