Tomcat源码阅读笔记 - Java Web Filter 调用链
11 October 2019
环境:
- Tomcat 9.0.17
Filter
通过FilterChain
调用链调用下一个”filter”,应用可在”filter”的public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
方法中调用”filterChain”的相关方法来传递请求到下一个”filter”中。
public interface FilterChain {
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException;
}
Filter
调用过程如下图所示,发起请求时ApplicationFilterChain
负责处理Filter
和Servlet
相关逻辑。
ApplicationFilterChain
的internalDoFilter
方法实现上述逻辑。pos
记录当前”filter”序号,每执行一次filter.doFilter
,pos
加1,直到执行完全部的”filter”,然后执行servlet.service
相关逻辑。也就是说应用可在执行filterChian.doFilter
完后添加自定义逻辑,即可保证在servlet.service
之后执行,从而达到修改response
等对象的目的。
// 调用 filter 和 servlet
// (省略无关代码, 完整代码查看 org.apache.catalina.core.ApplicationFilterChain)
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// 判断是否需要调用下一个 filter
// pos 为当前执行到的 filter 序号; n 为 filter 数量
if (pos < n) {
// 取出对应序号的 filter,然后加 1
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
...
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};
// 调用 filter.doFilter
SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
} else {
// 调用 filter.doFilter
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;
}
try {
...
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};
// 调用 servlet.service
SecurityUtil.doAsPrivilege("service",
servlet,
classTypeUsedInService,
args,
principal);
} else {
// 调用 servlet.service
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);
}
}
}