从SpringSecurity架构图可知SpringSecurity的过滤器与Web容器的过滤器是通过DelegatingFilterProxy接入的。由DelegatingFilterProxy代理了FilterChainProxy,FilterChainProxy包含了SpringSecurity的过滤器链。
那么DelegatingFilterProxy是怎么创建及如何加入到Web容器中?
看看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;
}
这个配置类创建了DelegatingFilterProxyRegistrationBean bean。
DelegatingFilterProxyRegistrationBean的类继承结构如下:
DelegatingFilterProxyRegistrationBean实现了ApplicationContextAware接口,可以注入ApplicationContext。还实现了ServletContextInitializer接口。ServletContextInitializer提供了配置Servlet 3.0+程序化接口。可以通过实现这个接口在SpringBoot启动时向web容器注入Servlet,Filter,Listener组件。
SpringBoot在启动时,会执行到AbstractApplicationContext#onRefresh()方法。ServletWebServerApplicationContext重写了onRefresh():
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
调用createWebServer()创建web容器。createWebServer()会执行到this.webServer = factory.getWebServer(getSelfInitializer());此代码。最终调用selfInitialize方法:
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareWebApplicationContext(servletContext);
registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
调用getServletContextInitializerBeans()方法创建ServletContextInitializerBeans。在ServletContextInitializerBeans构造函数中会去Spring容器中获取ServletContextInitializer类型的所有Bean。再到selfInitialize调用ServletContextInitializer#onStartup方法。ServletContextInitializer#onStartup向web容器注入Servlet,Filter,Listener组件。
ServletContextInitializer的子类有ServletListenerRegistrationBean,DynamicRegistrationBean。ServletListenerRegistrationBean负责向web容器注入Listener组件。DynamicRegistrationBean负责向web容器注入Servlet,Filter组件。DynamicRegistrationBean的子类有ServletRegistrationBean,AbstractFilterRegistrationBean。
ServletRegistrationBean负责向web容器注入Servlet组件。AbstractFilterRegistrationBean负责向web容器注入Filter组件。如果想向web容器加入Servlet,可以继承ServletRegistrationBean并设置Servlet即可。
ServletContextInitializer的子类RegistrationBean重写了onStartup:
public final void onStartup(ServletContext servletContext) throws ServletException {
String description = getDescription();
if (!isEnabled()) {
logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
return;
}
register(description, servletContext);
}
register负责注入组件。
DynamicRegistrationBean#register(String description, ServletContext servletContext)
protected final void register(String description, ServletContext servletContext) {
D registration = addRegistration(description, servletContext);
if (registration == null) {
logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");
return;
}
configure(registration);
}
configure配置异步web和初始化参数。addRegistration负责向web容器注入Servlet,Filter组件。
现在看看Filter的注入,即AbstractFilterRegistrationBean#addRegistration(String description, ServletContext servletContext):
protected Dynamic addRegistration(String description, ServletContext servletContext) {
Filter filter = getFilter();
return servletContext.addFilter(getOrDeduceName(filter), filter);
}
获取Filter然后加入ServletContext中。
AbstractFilterRegistrationBean子类又有FilterRegistrationBean,DelegatingFilterProxyRegistrationBean。FilterRegistrationBean用于SpringBoot向web容器注入Filter组件。如果我们想向web容器添加自定义filter,可以继承FilterRegistrationBean类,重写getFilter()方法即可。
DelegatingFilterProxyRegistrationBean#getFilter()
public DelegatingFilterProxy getFilter() {
return new DelegatingFilterProxy(this.targetBeanName, getWebApplicationContext()) {
@Override
protected void initFilterBean() throws ServletException {
// Don't initialize filter bean on init()
}
};
}
创建了DelegatingFilterProxy过滤器。注意DelegatingFilterProxy的构造函数的参数,targetBeanName是springSecurityFilterChain,还有WebApplicationContext。
DelegatingFilterProxy#doFilter
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) {
delegateToUse = this.delegate;
if (delegateToUse == null) {
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: " +
"no ContextLoaderListener or DispatcherServlet registered?");
}
delegateToUse = initDelegate(wac);
}
this.delegate = delegateToUse;
}
}
// Let the delegate perform the actual doFilter operation.
invokeDelegate(delegateToUse, request, response, filterChain);
}
initDelegate通过WebApplicationContext向Spring容器中获取名为targetBeanName的bean,即获取名为springSecurityFilterChain的Bean,也就是FilterChainProxy。invokeDelegate执行过滤器实际操作。
DelegatingFilterProxy#invokeDelegate
protected void invokeDelegate(
Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
delegate.doFilter(request, response, filterChain);
}
执行delegate的doFilter方法也就是执行FilterChainProxy的doFilter方法。此时就将SpringSecurity Filter与web容器的Filter连接起来。
标签:web,SpringBoot,容器,SpringSecurity,Filter,servletContext,DelegatingFilterProxy,Ser From: https://www.cnblogs.com/shigongp/p/17311457.html