Spring源码之DelegatingFilterProxy

本文深入剖析了Spring框架中的DelegatingFilterProxy组件,详细介绍了它的作用原理、核心属性及方法。此外,还探讨了它在Spring Security及Spring Boot中的具体应用。
摘要由CSDN通过智能技术生成

Spring源码之DelegatingFilterProxy

一、类图在这里插入图片描述

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

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

二、属性

@Nullable
	private String contextAttribute;

	//springmvc 上下文
	@Nullable
	private WebApplicationContext webApplicationContext;

	// 代理的filter的全名称,springmvc上下文通过此名称找到容器中的Filter赋值给delegate
	@Nullable
	private String targetBeanName;

	private boolean targetFilterLifecycle = false;

	//代理的filter
	@Nullable
	private volatile Filter delegate;

	private final Object delegateMonitor = new Object();

三、重要方法

	@Override
	protected void initFilterBean() throws ServletException {
		synchronized (this.delegateMonitor) {
			if (this.delegate == null) {
				// 如果没有设置targetBeanName,那么就使用filter的name当作targetBeanName
				if (this.targetBeanName == null) {
					this.targetBeanName = getFilterName();
				}
				// 通过springmvc容器获得代理的filter
				WebApplicationContext wac = findWebApplicationContext();
				if (wac != null) {
					// 获得代理的filter的方法
					this.delegate = initDelegate(wac);
				}
			}
		}
	}
	protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
		String targetBeanName = getTargetBeanName();
		Assert.state(targetBeanName != null, "No target bean name set");
		Filter delegate = wac.getBean(targetBeanName, Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}

核心方法

	@Override
	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 = findWebApplicationContext();
					if (wac == null) {
						throw new IllegalStateException("No WebApplicationContext found: " +
								"no ContextLoaderListener or DispatcherServlet registered?");
					}
					// 获取代理的filter类
					delegateToUse = initDelegate(wac);
				}
				this.delegate = delegateToUse;
			}
		}

		// 执行代理filter类的doFilter方法
		invokeDelegate(delegateToUse, request, response, filterChain);
	}
	protected void invokeDelegate(
			Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		
		delegate.doFilter(request, response, filterChain);
	}

四、SpringSecurity中的应用

一般会在web.xml配置,这个配置的作用就是使用DelegatingFilterProxy去代理springSecurityFilterChain的过滤器,所以过滤器名称必须叫springSecurityFilterChain,以方便在spring容器中找到这个过滤器。

<!--SpringSecurity过滤器链,注意过滤器名称必须叫springSecurityFilterChain-->
<filter>
	<filter-name>springSecurityFilterChain</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
	<filter-name>springSecurityFilterChain</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

五、Springboot中DelegatingFilterProxy怎么自动注入的?

  1. 在springboot自动配置jar包里面有一个org.springframework.boot.autoconfigure.security.servlet的自动配置包。它主要负责去导入一些security需要的配置。
    我们首先看SecurityAutoConfiguration这个自动配置类:
@Configuration
@ConditionalOnClass({DefaultAuthenticationEventPublisher.class})
@EnableConfigurationProperties({SecurityProperties.class})
// 这边会导入一些配置类,我们先看WebSecurityEnablerConfiguration
@Import({SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class, SecurityDataConfiguration.class})
public class SecurityAutoConfiguration {
    public SecurityAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean({AuthenticationEventPublisher.class})
    public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {
        return new DefaultAuthenticationEventPublisher(publisher);
    }
}

下面这个配置类有一个@EnableWebSecurity的注解,这个注解主要是开启websecurity的自动配置。

@Configuration
@ConditionalOnBean({WebSecurityConfigurerAdapter.class})
@ConditionalOnMissingBean(
    name = {"springSecurityFilterChain"}
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@EnableWebSecurity
public class WebSecurityEnablerConfiguration {
    public WebSecurityEnablerConfiguration() {
    }
}

来让我们看一下@EnableWebSecurity

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
// 这个注解也注入了一些配置类,我们主要看WebSecurityConfiguration
@Import({WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class})
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
    boolean debug() default false;
}

其中WebSecurityConfiguration就定义了springSecurityFilterChain是怎么注入容器中的。

@Configuration
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
    private WebSecurity webSecurity;
    private Boolean debugEnabled;
    private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
    private ClassLoader beanClassLoader;
    @Autowired(
        required = false
    )
    private ObjectPostProcessor<Object> objectObjectPostProcessor;

    public WebSecurityConfiguration() {
    }

    @Bean
    public static DelegatingApplicationListener delegatingApplicationListener() {
        return new DelegatingApplicationListener();
    }

    @Bean
    @DependsOn({"springSecurityFilterChain"})
    public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
        return this.webSecurity.getExpressionHandler();
    }
	// 这个方法就会向容器中注入springSecurityFilterChain的filter类。
    @Bean(
        name = {"springSecurityFilterChain"}
    )
    public Filter springSecurityFilterChain() throws Exception {
        boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
        if (!hasConfigurers) {
            WebSecurityConfigurerAdapter adapter = (WebSecurityConfigurerAdapter)this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {
            });
            this.webSecurity.apply(adapter);
        }
		// 通WebSecurity的build方法创建springSecurityFilterChain过滤器
        return (Filter)this.webSecurity.build();
    } 
    ......

我们重点看webSecurity.build()方法怎么玩的?

	public final O build() throws Exception {
		if (this.building.compareAndSet(false, true)) {
			// 通过doBuild方法得到
			this.object = doBuild();			
			return this.object;
		}
		throw new AlreadyBuiltException("This object has already been built");
	}
	// 继续追踪,跳到了AbstractConfiguredSecurityBuilder类里面
	@Override
	protected final O doBuild() throws Exception {
		synchronized (configurers) {
			buildState = BuildState.INITIALIZING;

			beforeInit();
			init(); // 会遍历所有的 WebSecurityConfigurerAdapter ,并执行其 init 方法。

			buildState = BuildState.CONFIGURING;

			beforeConfigure();
			configure(); // configure 方法会遍历所有的 WebSecurityConfigurerAdapter ,并执行其 configure 方法。

			buildState = BuildState.BUILDING;
			// 调用了performBuild方法得到
			O result = performBuild();

			buildState = BuildState.BUILT;

			return result;
		}
	}
	// 继续追踪,我们使用WebSecurity的实现方法,跳到了WebSecurity类
	@Override
	protected Filter performBuild() throws Exception {
		Assert.state(
				!securityFilterChainBuilders.isEmpty(),
				() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
						+ "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
						+ "More advanced users can invoke "
						+ WebSecurity.class.getSimpleName()
						+ ".addSecurityFilterChainBuilder directly");
		int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
		// 这里将SecurityFilterChain过滤链集合给定义好
		List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
				chainSize);
		for (RequestMatcher ignoredRequest : ignoredRequests) {
			securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
		}
		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
			securityFilterChains.add(securityFilterChainBuilder.build());
		}
		// 这边可以看到返回的springSecurityFilterChain就是new的FilterChainProxy,并将SecurityFilterChain过滤链集合传过去。
		FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
		if (httpFirewall != null) {
			filterChainProxy.setFirewall(httpFirewall);
		}
		filterChainProxy.afterPropertiesSet();

		Filter result = filterChainProxy;
		if (debugEnabled) {
			logger.warn("\n\n"
					+ "********************************************************************\n"
					+ "**********        Security debugging is enabled.       *************\n"
					+ "**********    This may include sensitive information.  *************\n"
					+ "**********      Do not use in a production system!     *************\n"
					+ "********************************************************************\n\n");
			result = new DebugFilter(filterChainProxy);
		}
		postBuildAction.run();
		return result;
	}

当容器中有上面的springSecurityFilterChain类后,就将DelegatingFilterProxy也注入了进去,并设置targetBeanName为springSecurityFilterChain。

@Configuration
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@EnableConfigurationProperties({SecurityProperties.class})
@ConditionalOnClass({AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class})
@AutoConfigureAfter({SecurityAutoConfiguration.class})
public class SecurityFilterAutoConfiguration {
    private static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";

    public SecurityFilterAutoConfiguration() {
    }

    @Bean
    @ConditionalOnBean(
        name = {"springSecurityFilterChain"}
    )
    public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(SecurityProperties securityProperties) {
        DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean("springSecurityFilterChain", new ServletRegistrationBean[0]);
        registration.setOrder(securityProperties.getFilter().getOrder());
        registration.setDispatcherTypes(this.getDispatcherTypes(securityProperties));
        return registration;
    }

那么springSecurityFilterChain究竟是什么类?
上面我们知道springSecurityFilterChain是FilterChainProxy,它是属于springsecurity的一个过滤类,和DelegatingFilterProxy一样继承了GenericFilterBean

// 有删减
public class FilterChainProxy extends GenericFilterBean {
	// 保存了多个SecurityFilterChain类型的过滤器链
    private List<SecurityFilterChain> filterChains;
	// 核心方法
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
        if (clearContext) {
            try {
                request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
                //实际调用这个方法
                this.doFilterInternal(request, response, chain);
            } finally {
                SecurityContextHolder.clearContext();
                request.removeAttribute(FILTER_APPLIED);
            }
        } else {
            this.doFilterInternal(request, response, chain);
        }

    }
    // 实际调用的方法
    private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        FirewalledRequest fwRequest = this.firewall.getFirewalledRequest((HttpServletRequest)request);
        HttpServletResponse fwResponse = this.firewall.getFirewalledResponse((HttpServletResponse)response);
        // 获得匹配成功的过滤器链中的过滤器集合
        List<Filter> filters = this.getFilters((HttpServletRequest)fwRequest);
        if (filters != null && filters.size() != 0) {
        	// 运行获得的过滤器集合
            FilterChainProxy.VirtualFilterChain vfc = new FilterChainProxy.VirtualFilterChain(fwRequest, chain, filters);
            vfc.doFilter(fwRequest, fwResponse);
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug(UrlUtils.buildRequestUrl(fwRequest) + (filters == null ? " has no matching filters" : " has an empty filter list"));
            }

            fwRequest.reset();
            chain.doFilter(fwRequest, fwResponse);
        }
    }
    // 通过遍历过滤器链集合获得过滤器集合
    private List<Filter> getFilters(HttpServletRequest request) {
        Iterator var2 = this.filterChains.iterator();

        SecurityFilterChain chain;
        do {
            if (!var2.hasNext()) {
                return null;
            }

            chain = (SecurityFilterChain)var2.next();
          // 需要经过 chain.matches(request) 判断到底哪个过滤器链匹配成功,每个 request 最多只会经过一个 SecurityFilterChain。
        } while(!chain.matches(request));

        return chain.getFilters();
    }

List<SecurityFilterChain> filterChains 到底保存了哪些filter呢?
就是常用的一些Spring Security过滤器(SpringSecurity有介绍)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值