DelegatingFilterProxy源码解析

本文介绍了在web项目中使用DelegatingFilterProxy作为代理来实现与Spring的集成,详细解析了其源码,包括init方法的执行流程、doFilter方法如何调用实际过滤逻辑,以及targetFilterLifecycle参数在初始化和销毁过程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0.引言

在web项目中写过滤器时,若想使用sprng的某些功能,可以通过DelegatingFilterProxy类来实现,该类相当于一个代理类,它会通过配置的filter-name的值去spring容器中找到对应的bean,并且执行对应的过滤逻辑。

1.使用方式

<filter>
		<filter-name>filter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<init-param>
			<param-name>targetFilterLifecycle</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>filter</filter-name>
		<url-pattern>/admin/*</url-pattern>
	</filter-mapping>

2.源码解析

在这里插入图片描述
通过类关系图可知,DelegatingFilterPorxy是一个过滤器,那么它是如何调用spring容器中的bean来执行操作的呢?

1.执行过滤器的init方法

DelegatingFilterProxy类中并没有init方法的实现,该实现在他的父类GenericFilterBean当中,在父类中找到该方法。
GenericFilterBean.class

public final void init(FilterConfig filterConfig) throws ServletException {
		Assert.notNull(filterConfig, "FilterConfig must not be null");
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing filter '" + filterConfig.getFilterName() + "'");
		}

		this.filterConfig = filterConfig;

		// 将init parameters参数设置成spring能够管理的结构
		try {
			PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);
			BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
			ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());
			bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));
			initBeanWrapper(bw);
			bw.setPropertyValues(pvs, true);
		}
		catch (BeansException ex) {
			String msg = "Failed to set bean properties on filter '" +
				filterConfig.getFilterName() + "': " + ex.getMessage();
			logger.error(msg, ex);
			throw new NestedServletException(msg, ex);
		}

		// 这里就是DelegatingFilterProxy类能够从sping容器中获取对应bean的核心
		initFilterBean();

		if (logger.isDebugEnabled()) {
			logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully");
		}
	}

initFilterBean()是在DelegatingFilterProxy类中实现的方法,代码如下:
DelegatingFilterProxy.class

@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) {
					//获取filter-name的值作为待获取bean的id,如果没有将使用DelegatingFilterProxy的bean id.
					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) {
					//在这里通过targetBeanName从Spring容器中获取对应的bean
					this.delegate = initDelegate(wac);
				}
			}
		}
	}

initDelegate(wac)代码如下:
DelegatingFilterProxy.class

protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
		//将获取的bean赋值给delegate,之后执行doFilter方法时将会调用该bean的方法。
		Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}

通过执行init方法将对应的bean赋值给this.delegate后,过滤器将执行doFilter方法。

2.执行doFilter方法

DelegatingFilterProxy.class

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

doFilter中通过调用invokeDelegate方法来执行实际的过滤逻辑。

protected void invokeDelegate(
			Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		//这里将会执行从spring容器获取的bean的doFilter方法。
		delegate.doFilter(request, response, filterChain);
	}
4.targetFilterLifecycle的作用

通过init-param将targetFilterLifecycle设置为true,可以让DelegatingFilterProxy代理的filter bean里init和destroy方法生效。在DelegatingFilterProxy调用init时会根据该参数来决定是否调用该bean中的init方法。

protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
		Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}
protected boolean isTargetFilterLifecycle() {
		return this.targetFilterLifecycle;
	}

在调用destroy时会根据该参数来决定是否调用该bean中的destroy方法。

@Override
public void destroy() {
	Filter delegateToUse = this.delegate;
	if (delegateToUse != null) {
		destroyDelegate(delegateToUse);
	}
}
protected void destroyDelegate(Filter delegate) {
	if (isTargetFilterLifecycle()) {
		delegate.destroy();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值