引言

filter是Servlet的规范,是在请求进入容器后,执行Servlet.service方法之前执行。
Tomcat处理filter分为三步:

  • 上下文初始化时读取web.xml中的filter数据
  • 请求处理时,根据请求路径找到相应的过滤器
  • 执行过滤器链,调用doFilter方法与目标方法。

初始化filter数据

首先在ContextConfig初始化时,读取web.xml配置文件,将其中的filter信息封装为FilterDef存储到StandardContext:

1
2
3
4
5
6
7
8
9
10
11
12
13
private void configureContext(WebXml webxml) {
//略......
for (FilterDef filter : webxml.getFilters().values()) {
if (filter.getAsyncSupported() == null) {
filter.setAsyncSupported("false");
}
context.addFilterDef(filter);
}
for (FilterMap filterMap : webxml.getFilterMappings()) {
context.addFilterMap(filterMap);
}
//略......
}

之后在StandardContext初始化时调用filterStart,组装好filterConfigs供后期使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Configure and initialize the set of filters for this Context.
* @return <code>true</code> if all filter initialization completed
* successfully, or <code>false</code> otherwise.
*/
public boolean filterStart() {

if (getLogger().isDebugEnabled()) {
getLogger().debug("Starting filters");
}
// Instantiate and record a FilterConfig for each defined filter
boolean ok = true;
synchronized (filterConfigs) {
filterConfigs.clear();
for (Entry<String,FilterDef> entry : filterDefs.entrySet()) {
String name = entry.getKey();
if (getLogger().isDebugEnabled()) {
getLogger().debug(" Starting filter '" + name + "'");
}
try {
//这里会调用 Filter.init 方法
ApplicationFilterConfig filterConfig =
new ApplicationFilterConfig(this, entry.getValue());
filterConfigs.put(name, filterConfig);
} catch (Throwable t) {
t = ExceptionUtils.unwrapInvocationTargetException(t);
ExceptionUtils.handleThrowable(t);
getLogger().error(sm.getString(
"standardContext.filterStart", name), t);
ok = false;
}
}
}

return ok;
}

创建过滤器链

创建过滤器链方法调用位于StandardWrapperValve的invoke中:

1
2
3
 //为这个请求创建过滤器链
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

进入ApplicationFilterFactory中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/**
* 构造一个FilterChain实现,它将封装指定servlet实例的执行。
*
* @param request 我们正在处理的servlet请求,javax.servlet.ServletRequest
* @param wrapper 管理servlet实例的包装器 org.apache.catalina.Wrapper
* @param servlet 要包装的servlet实例 javax.servlet.Servlet
* @return 配置的FilterChain实例,如果不执行,则为null。
*/
public static ApplicationFilterChain createFilterChain(ServletRequest request,
Wrapper wrapper, Servlet servlet) {

// 如果没有要执行的servlet,则返回null
if (servlet == null)
return null;

// 创建并初始化过滤器链对象
ApplicationFilterChain filterChain = null;
//这里的Request为org.apache.catalina.connector.Request
if (request instanceof Request) {
Request req = (Request) request;
//SecurityManager是否打开
if (Globals.IS_SECURITY_ENABLED) {
// Security: Do not recycle 不回收
filterChain = new ApplicationFilterChain();
} else {
//从请求中获取ApplicationFilterChain,也就是回收的
filterChain = (ApplicationFilterChain) req.getFilterChain();
if (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} else {
// 正在使用的请求调度程序,ApplicationDispatcher调用过来的
filterChain = new ApplicationFilterChain();
}

//设置将在这个链的末尾执行的servlet。
filterChain.setServlet(servlet);
//关联的servlet实例是否支持异步处理?
filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());

// 获取此上下文的过滤器映射
StandardContext context = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps();

// 如果没有过滤器映射,我们就完成了
if ((filterMaps == null) || (filterMaps.length == 0))
return filterChain;

// 获取匹配筛选器映射所需的信息
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();

//将相关的路径映射过滤器添加到此过滤器链
for (int i = 0; i < filterMaps.length; i++) {
//dispatcher类型与FilterMap中指定的dispatcher类型是否匹配
if (!matchDispatcher(filterMaps[i], dispatcher)) {
continue;
}
//上下文相关的请求路径符合指定的筛选器映射的要求
if (!matchFiltersURL(filterMaps[i], requestPath))
continue;
//从上下文context中获取ApplicationFilterConfig
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
//将过滤器添加到将在此链中执行的过滤器集中。
filterChain.addFilter(filterConfig);
}

// 添加与servlet名称第二次匹配的过滤器
for (int i = 0; i < filterMaps.length; i++) {
//dispatcher类型与FilterMap中指定的dispatcher类型是否匹配
if (!matchDispatcher(filterMaps[i], dispatcher)) {
continue;
}
//如果指定的servlet名称符合指定的筛选器映射的要求
if (!matchFiltersServlet(filterMaps[i], servletName))
continue;
//从上下文context中获取ApplicationFilterConfig
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
//将过滤器添加到将在此链中执行的过滤器集中。
filterChain.addFilter(filterConfig);
}

最终过滤器加入了ApplicationFilterConfig数组的末尾。

执行过滤器链

1
filterChain.doFilter(request.getRequest(), response.getResponse());

最终会调用到ApplicationFilterChain的internalDoFilter方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
private void internalDoFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {

// 如果有一个过滤器,调用下一个过滤器
//pos:过滤器链中当前位置的索引。
//n:链中过滤器当前数量
if (pos < n) {
//获取过滤器配置
ApplicationFilterConfig filterConfig = filters[pos++];
try {
//获取过滤器,会调用:filter.init
Filter filter = filterConfig.getFilter();

//异步处理
if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
//调用doFilter,处理完过滤逻辑之后还会继续调用当前过滤器链的doFilter方法
if (Globals.IS_SECURITY_ENABLED) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();

Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
} else {
filter.doFilter(request, response, this);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}

// We fell off the end of the chain -- call the servlet instance
//准备调用servlet.service方法
try {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}

if (request.isAsyncSupported() && !servletSupportsAsync) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
// Use potentially wrapped request from this point
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse) &&
Globals.IS_SECURITY_ENABLED) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res};
SecurityUtil.doAsPrivilege("service",
servlet,
classTypeUsedInService,
args,
principal);
} else {
//执行业务逻辑
servlet.service(request, response);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.servlet"), e);
} finally {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(null);
lastServicedResponse.set(null);
}
}
}

其中filter.doFilter,处理完过滤逻辑之后还会继续调用当前过滤器链的doFilter方法,直到所有过滤器链处理完毕。
最后执行Servlet的service方法,处理业务逻辑。

基本上将调用链的逻辑分析完了,下一篇简单的总结一下整个请求处理过程。