java 中filter的执行顺序是怎样的

问题：

filterChain 是什么时候执行的呢？

filterChain 中的 filter 来源何处？

standardContext 什么时候开始收集的过滤器集合

1. filterChain 是什么时候执行的呢？

在org.apache.catalina.core.StandardWrapperValve 类中有如下一个方法

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

我们一会儿回过头来看它是如何创建过滤器链对象的代码，我们先来看他是如何执行过滤器链的，过滤器链对象执行的流程实现:

Copy
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 方法中

Copy
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

Copy
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 类中

Copy
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()

查看方法

Copy
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 对象