问题:#
- filterChain 是什么时候执行的呢?
- filterChain 中的 filter 来源何处?
- standardContext 什么时候开始收集的过滤器集合
1. filterChain 是什么时候执行的呢?#
在org.apache.catalina.core.StandardWrapperValve
类中有如下一个方法
public final void invoke(Request request, Response response)
throws IOException, ServletException {
//省略掉大段无关代码
Servlet servlet = null;
Context context = (Context) wrapper.getParent();
//省略掉大段无关代码
try {
if (!unavailable) {
//1.create servlet
servlet = wrapper.allocate();
}
} catch(){
...
}
// 2. Create the filter chain for this request
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
Container container = this.container;
try {
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
//execute doFilter method of the FilterChain object.
filterChain.doFilter(request.getRequest(),
response.getResponse());
}
} finally {
}
} else {
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}
}
} catch(){
} finally {
// Release the filter chain (if any) for this request
if (filterChain != null) {
filterChain.release();
}
// Deallocate the allocated servlet instance
try {
if (servlet != null) {
wrapper.deallocate(servlet);
}
}
}
}
我们一会儿回过头来看它是如何创建过滤器链对象的代码,我们先来看他是如何执行过滤器链的,过滤器链对象执行的流程实现:
public final class ApplicationFilterChain implements FilterChain {
//cur executing filter index
private int pos = 0;
//matched filter count
private int n = 0;
//servlet
private Servlet servlet = null;
//matched filter arrays
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
//security been turned on
if( Globals.IS_SECURITY_ENABLED ) {
//... security bean filter
} else {
//execute filter logic
internalDoFilter(request,response);
}
}
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// loop and Call the next filter if there is one
if (pos < n) {
//pos index ++
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
if( Globals.IS_SECURITY_ENABLED ) {
} else {
//execute the doFilter() of the cur filter in the filter chain
filter.doFilter(request, response, this);
}
} catch(){
...
}
return;
}
// We fell off the end of the chain -- call the servlet instance
try {
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse) &&
Globals.IS_SECURITY_ENABLED ) {
} else {
//if there are no filters to be executed, the servlet's service method will be executed, which contains the business logic that we have written.
servlet.service(request, response);
}
}catch(){
...
}finally{
...
}
}
}
从 filterChain 类的源码可以看出底层是包含了 所匹配上的 filter 数组 也就是添加进去匹配上过滤器对象是有序的,添加的时候就决定了。
那么它是什么时候添加的呢?
2. filterChain 中的 filter 来源何处?#
其实在org.apache.catalina.core.StandardWrapperValve
类的 invoke 方法中
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
public static ApplicationFilterChain createFilterChain(ServletRequest request,
Wrapper wrapper, Servlet servlet) {
// If there is no servlet to execute, return null
if (servlet == null)
return null;
// Create and initialize a filter chain object
ApplicationFilterChain filterChain = null;
if (request instanceof Request) {
Request req = (Request) request;
if (Globals.IS_SECURITY_ENABLED) {
// Security: Do not recycle
filterChain = new ApplicationFilterChain();
} else {
filterChain = (ApplicationFilterChain) req.getFilterChain();
if (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} else {
// Request dispatcher in use
filterChain = new ApplicationFilterChain();
}
filterChain.setServlet(servlet);
filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());
// Acquire the filter mappings for this Context
StandardContext context = (StandardContext) wrapper.getParent();
//Get an array of all the filters registered in the ServletContext object
FilterMap filterMaps[] = context.findFilterMaps();
// If there are no filter mappings, we are done
if ((filterMaps == null) || (filterMaps.length == 0))
return filterChain;
// Acquire the information we will need to match filter mappings
DispatcherType dispatcher =
(DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);
String requestPath = null;
Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
if (attribute != null){
requestPath = attribute.toString();
}
String servletName = wrapper.getName();
// Add the relevant path-mapped filters to this filter chain
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
if (!matchFiltersURL(filterMaps[i], requestPath))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
}
// Add filters that match on servlet name second
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
if (!matchFiltersServlet(filterMaps[i], servletName))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
}
// Return the completed filter chain
return filterChain;
}
可以看出在创建 filterChain 对象时候,从 ServletContext 获取所有注册的 filter 的数组取出需要的添加到这次请求创建的 filterChain 对象,而且 servletContext 对象的注册的所有的过滤器本身就是一个数组(本身就是有序的), 所以遍历匹配的时候,也就是有序的。
3. ServletContext 什么时候开始收集的数组#
filterMaps 在 StandardContext 类中
public class StandardContext extends ContainerBase
implements Context, NotificationEmitter {
private final ContextFilterMaps filterMaps = new ContextFilterMaps();
//
@Override
public void addFilterMap(FilterMap filterMap) {
validateFilterMap(filterMap);
// Add this filter mapping to our registered set
filterMaps.add(filterMap);
fireContainerEvent("addFilterMap", filterMap);
}
}
启动 tomcat,我们可以根据堆栈查看调用顺序
StandardContext.startInternal()
-->fireLifecycleEvent()
-->ContextConfig.lifecycleEvent()
-->ContextConfig.lifecycleEventcon
-->ContextConfig.con.figureStart()
-->ContextConfig.webConfig()
查看方法
protected void webConfig() {
if (ok) {
configureContext(webXml);
}
}
private void configureContext(WebXml webxml) {
for (FilterMap filterMap : webxml.getFilterMappings()) {
context.addFilterMap(filterMap);
}
}
这里就将 web.xml 收集到所有 filter 的 set 集合,然后将收集到的 filter 集合转换成数组,设置给 StandardContext 对象