概述
Tomcat的类ApplicationFilterChain是一个Java Servlet API规范javax.servlet.FilterChain的实现,用于管理某个请求request的一组过滤器Filter的执行。当针对一个request所定义的一组过滤器Filter处理完该请求后,组后一个doFilter()调用才会执行目标Servlet的方法service(),然后响应对象response会按照相反的顺序依次被这些Filter处理,最终到达客户端。
事实上,一个Filter的逻辑可以被设计成既可以在目标servlet执行前执行,也可以在目标servlet执行之后执行,或者二者都有,甚至可以不执行目标servlet而是自己直接响应客户端。因此,在一个ApplicationFilterChain链执行到目标servlet实例的service()方法时,你可以认为此时所有Filter被设计在servlet执行之前执行的逻辑都执行完了,而所有Filter的被设计在servlet执行之后执行的逻辑都还尚未执行。
源代码分析
/** 此源代码摘自Tomcat版本9*/public final class ApplicationFilterChain implements FilterChain {// Used to enforce requirements of SRV.8.2 / SRV.14.2.5.1private static final ThreadLocal<ServletRequest> lastServicedRequest;private static final ThreadLocal<ServletResponse> lastServicedResponse;static {if (ApplicationDispatcher.WRAP_SAME_OBJECT) {lastServicedRequest = new ThreadLocal<>();lastServicedResponse = new ThreadLocal<>();} else {lastServicedRequest = null;lastServicedResponse = null;}}// -------------------------------------------------------------- Constantspublic static final int INCREMENT = 10;// ----------------------------------------------------- Instance Variables/*** Filters. 执行目标Servlet.service()方法前需要经历的过滤器Filter,初始化为0个元素的数组对象*/private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];/*** The int which is used to maintain the current position* in the filter chain.* 用于记录过滤器链中当前所执行的过滤器的位置,是当前过滤器在filters数组的下标,初始化为0*/private int pos = 0;/*** The int which gives the current number of filters in the chain.* 过滤器链中过滤器的个数(注意:并不是数组filters的长度),初始化为0,和filters数组的初始长度一致*/private int n = 0;/*** The servlet instance to be executed by this chain.* 该过滤器链执行完过滤器后最终要执行的目标Servlet*/private Servlet servlet = null;/*** Does the associated servlet instance support async processing?* 所关联的Servlet实例是否支持异步处理 ? 缺省为 false,表示缺省情况下不支持异步处理。*/private boolean servletSupportsAsync = false;/*** The string manager for our package.*/private static final StringManager sm =StringManager.getManager(Constants.Package);/*** Static class array used when the SecurityManager is turned on and* <code>doFilter</code> is invoked.*/private static final Class<?>[] classType = new Class[]{ServletRequest.class, ServletResponse.class, FilterChain.class};/*** Static class array used when the SecurityManager is turned on and* <code>service</code> is invoked.*/private static final Class<?>[] classTypeUsedInService = new Class[]{ServletRequest.class, ServletResponse.class};// ---------------------------------------------------- FilterChain Methods/*** Invoke the next filter in this chain, passing the specified request* and response. If there are no more filters in this chain, invoke* the <code>service()</code> method of the servlet itself.* 执行过滤器链中的下一个过滤器Filter。如果链中所有过滤器都执行过,* 则调用servlet的service()方法。** @param request The servlet request we are processing* @param response The servlet response we are creating** @exception IOException if an input/output error occurs* @exception ServletException if a servlet exception occurs*/@Overridepublic void doFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException {// 下面的if-else分支主要是根据Globals.IS_SECURITY_ENABLED是true还是false决定// 如何调用目标逻辑,但两种情况下,目标逻辑最终都是 internalDoFilter(req,res)if( Globals.IS_SECURITY_ENABLED ) {final ServletRequest req = request;final ServletResponse res = response;try {java.security.AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<Void>() {@Overridepublic Void run()throws ServletException, IOException {internalDoFilter(req,res);return null;}});} catch( PrivilegedActionException pe) {Exception e = pe.getException();if (e instanceof ServletException)throw (ServletException) e;else if (e instanceof IOException)throw (IOException) e;else if (e instanceof RuntimeException)throw (RuntimeException) e;elsethrow new ServletException(e.getMessage(), e);}} else {internalDoFilter(request,response);}}private void internalDoFilter(ServletRequest request,ServletResponse response)throws IOException, ServletException {// Call the next filter if there is oneif (pos < n) {ApplicationFilterConfig filterConfig = filters[pos++];try {// 找到目标 Filter 对象Filter filter = filterConfig.getFilter();if (request.isAsyncSupported() && "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);}// 执行目标 Filter 对象的 doFilter方法,// 注意,这里当前ApplicationFilterChain对象被传递到了目标// Filter对象的doFilter方法,而目标Filter对象的doFilter在执行完自己// 被指定的逻辑之后会反过来调用这个ApplicationFilterChain对象的// doFilter方法,只是pos向前推进了一个过滤器。这个ApplicationFilterChain// 和Filter之间反复调用彼此doFilter方法的过程一直持续直到当前链发现所有的// Filter都已经被执行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实例本身了。// !!! 注意 : 虽然这里开始调用servlet实例了,但是从当前方法执行堆栈可以看出,过滤器链// 和链中过滤器的doFilter方法的执行帧还在堆栈中并未退出,他们会在servlet实例的逻辑// 执行完后,分别执行完自己剩余的的逻辑才会逐一结束。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 pointif ((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);}}}/*** The last request passed to a servlet for servicing from the current* thread.** @return The last request to be serviced.*/public static ServletRequest getLastServicedRequest() {return lastServicedRequest.get();}/*** The last response passed to a servlet for servicing from the current* thread.** @return The last response to be serviced.*/public static ServletResponse getLastServicedResponse() {return lastServicedResponse.get();}// -------------------------------------------------------- Package Methods/*** Add a filter to the set of filters that will be executed in this chain.* 往当前要执行的过滤器链的过滤器集合filters中增加一个过滤器* @param filterConfig The FilterConfig for the servlet to be executed*/void addFilter(ApplicationFilterConfig filterConfig) {// Prevent the same filter being added multiple times//去重处理,如果已经添加进来则避免二次添加for(ApplicationFilterConfig filter:filters)if(filter==filterConfig)return;if (n == filters.length) {// !!! 请注意:每次需要扩容时并不是增加一个元素空间,而是增加INCREMENT(默认是10)个,// 这个行为的结果是filters数组的长度和数组中过滤器的个数n并不相等ApplicationFilterConfig[] newFilters =new ApplicationFilterConfig[n + INCREMENT];System.arraycopy(filters, 0, newFilters, 0, n);filters = newFilters;}filters[n++] = filterConfig;}/*** Release references to the filters and wrapper executed by this chain.*/void release() {for (int i = 0; i < n; i++) {filters[i] = null;}n = 0;pos = 0;servlet = null;servletSupportsAsync = false;}/*** Prepare for reuse of the filters and wrapper executed by this chain.*/void reuse() {pos = 0;}/*** Set the servlet that will be executed at the end of this chain.** @param servlet The Wrapper for the servlet to be executed*/void setServlet(Servlet servlet) {this.servlet = servlet;}void setServletSupportsAsync(boolean servletSupportsAsync) {this.servletSupportsAsync = servletSupportsAsync;}/*** Identifies the Filters, if any, in this FilterChain that do not support* async.** @param result The Set to which the fully qualified class names of each* Filter in this FilterChain that does not support async will* be added*/public void findNonAsyncFilters(Set<String> result) {for (int i = 0; i < n ; i++) {ApplicationFilterConfig filter = filters[i];if ("false".equalsIgnoreCase(filter.getFilterDef().getAsyncSupported())) {result.add(filter.getFilterClass());}}}}
