tomcat + spring mvc原理(五):tomcat Filter组件实现原理
- 前言:
- Wrapper中Pipeline的收尾
- Filter的基本实现
- FilterChain的实现
前言:
原理(四)中假装结束了tomcat消息处理的流程分析,其实偷偷留了私货–Filter的这个部分依然属于tomcat网络消息处理的一个步骤。
Wrapper中Pipeline的收尾
原理(四)最后用Wrapper中的StandardWrapperValve收尾,结论是
StandardWrapperValve是tomcat处理消息的边界,在这个Value的invoke()方法中,消息被传递给了Servlet,从此进入了spring mvc的领域。
StandardWrapperValve的invoke方法的实现代码很长,不过大部分内容都是异常的catch和处理,核心主要是获取Servlet实例、构建FilterChain、判断是否是异步Servlet和执行filterChain.doFilter方法。
······
servlet = wrapper.allocate();
······
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
······
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
······
filterChain看上去很像原理(四)介绍的责任链,请求先依次经过注册Filter的处理,在最后会调用Servlet的service方法.到达Servlet就意味着请求被传递到了spring mvc中。Servlet的默认实现是DispatcherServlet,这部分内容会在spring mvc模块详细介绍。
Filter的基本实现
public interface Filter {
public default void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException;
public default void destroy() {}
}
在业务逻辑中添加Filter,就需要实现这个接口。FilterChain调用doFilter()方法时,依次调用注册的Filter的doFilter()方法,Filter是FilterChain中的基本单元。实际上,FilterChain中维护的是一个ApplicationFilterConfig的数组,这是因为在调用doFilter时,并不能保证Filter的实现类已经被加载到内存中,但是每一个注册过的Filter的类名(spring mvc在配置文件中配置,spring boot加载方式复杂一点)都会被保存在Context中。ApplicationFilterConfig中既有String变量保存类名,也有Filter的引用获取已经构造好的实例对象。
public final class ApplicationFilterConfig implements FilterConfig, Serializable {
·····
private final transient Context context;
private transient Filter filter = null;
private final FilterDef filterDef;
·····
}
其中的FilterDef中就存储了filterClass的名字,这样在需要获取类实例时,就能直接newInstance()一个实例。
FilterChain的实现
FilterChain中存储了ApplicationFilterConfig的数组,整数n用来存储数组的大小,整数pos用来存储当前调用的Filter的index。FilterChain的doFilter()实际调用internalDoFilter()来实现Filter链的遍历。首先是获取当前位置的Filter的实例,如果Filter的实现类的实例已经加载,filterConfig.getFilter()能够直接获取,如果没有加载,则根据类名构造一个实例。然后调用filter.doFilter(),其中传入了请求消息体、应答消息体和FilterChain自身。由于这个Filter的遍历并不是由循环而是由递归实现的,所以filter的doFilter()方法最后需要再次调用FilterChain的doFilter方法,这样FilterChain可以pos++,执行下一个filter的doFilter()。
public final class ApplicationFilterChain implements FilterChain {
......
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
private int pos = 0;
private int n = 0;
private Servlet servlet = null;
......
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
......
} else {
filter.doFilter(request, response, this);
}
......
} else {
servlet.service(request, response);
}
......
}
在所有注册的Filter都遍历一遍之后,FilterChain会调用Servlet的service方法处理请求,自此,请求正式进入到spring mvc的领域。
最后解释一下ApplicationFilterFactory。ApplicationFilterFactory中的createFilterChain()方法中构造了一个ApplicationFilterChain对象,然后能够从Context中获得FilterMap,由这个FilterMap的内容填充了FilterChain的对象,这是就是FilterChain实现初始化的关键点。