1.前景提要
springSecurityFilterChain
是一个DelegatingFilterProxyRegistrationBean
的对象。
感谢青稚774
老哥的指正。
springSecurityFilterChain是先通过spring的autoconfiguration注入spring容器中,然后被DelegatingFilterProxyRegistrationBean注入到servlet容器中。
所以说 【springSecurityFilterChain是一个
DelegatingFilterProxyRegistrationBean`的对象】 这句话是错的。
springSecurityFilterChain是DelegatingFilterProxyRegistrationBean注册目标,将它注册到servlet容器中。
在第二篇中,我们分析得知,spring security通过注入DelegatingFilterProxyRegistrationBean
对象到spring 容器中来使 servlet 容器在初始化的过程中能够获取并初始化到自己的过滤器链中去。
2.加入servlet 容器拦截器链中的springSecurityFilterChain如何运作
这里先从tomcat拦截器链开始,tomcat是接受请求的容器,由它负责处理请求并转到对应的应用中去。
大致流程:
- Socket监听
- Protocol协议解析
CoyoteAdapter
将解析出的数据转为Request和Response(也就是适配为同样格式数据)- Engine 开始根据请求选择对应的Host应用程序来处理这个请求
- 每个Host根据对应的URL来选择Context
- 每个Context包含一个对应的servlet包装类(Wrapper),在springmvc中,tomcat的
Wrapper
包含的就是DispatcherServlet
- 在这个
Wrapper
中会创建一个ApplicationFilterChain
,这个拦截器链就是从servlet容器中获取的 - 这个拦截器链中就包含前面设置进去的
springSecurityFilterChain
。
上面就是从tomcat 到 springSecurityFilterChain
的大致流程。
3. ApplicationFilterChain之tomcat拦截器链的构建过程
1.基于ApplicationFilterFactory
创建拦截器链
2.从StandardContext
中获取拦截器数组
3.添加拦截器到ApplicationFilterChain
但是这里估计有人会有点疑问,spring 明明是将filter设置到ServletContext
,怎么tomcat 获取拦截器的时候,是从StandardContext
中获取的呢?
4.ServletContext 将 filter 注入到StandardContext
ServletContext是一个接口,其默认实现为ApplicationContext
而ApplicationContext
是持有StandardContext
的
这个时候就需要看看addFilter方法了,这个是我们将filter添加到servletContext的方法。
private FilterRegistration.Dynamic addFilter(String filterName,
String filterClass, Filter filter) throws IllegalStateException {
if (filterName == null || filterName.equals("")) {
throw new IllegalArgumentException(sm.getString(
"applicationContext.invalidFilterName", filterName));
}
if (!context.getState().equals(LifecycleState.STARTING_PREP)) {
//TODO Spec breaking enhancement to ignore this restriction
throw new IllegalStateException(
sm.getString("applicationContext.addFilter.ise",
getContextPath()));
}
// 可以看到是从StandardContext获取FilterDef
FilterDef filterDef = context.findFilterDef(filterName);
// Assume a 'complete' FilterRegistration is one that has a class and
// a name
if (filterDef == null) {
filterDef = new FilterDef();
filterDef.setFilterName(filterName);
// 添加filter 也是添加到StandardContext
context.addFilterDef(filterDef);
} else {
if (filterDef.getFilterName() != null &&
filterDef.getFilterClass() != null) {
return null;
}
}
if (filter == null) {
filterDef.setFilterClass(filterClass);
} else {
filterDef.setFilterClass(filter.getClass().getName());
filterDef.setFilter(filter);
}
return new ApplicationFilterRegistration(filterDef, context);
}
从上面可以看到其实ServletContext
的filter信息,其实是放在StandardContext
中进行存储的。
所以也就是为啥能通过StandardContext
获取filter数组了。
5.小结
整个过程其实就是创建ApplicationFilterChain
,然后从servletContext
中获取过滤器数组加入到拦截器链中。
一张图小结一下: