Tomcat 的 ApplicationFilterChain
2018-01-11 10:50
316 查看
概述
Tomcat的类ApplicationFilterChain是一个Java Servlet API规范javax.servlet.FilterChain的实现,用于管理某个请求request的一组过滤器Filter的执行。当针对一个request所定义的一组过滤器Filter执行完后,下一个doFilter()调用就会执行目标Servlet的方法service()。需要注意的是,这里针对一个request所定义的一组过滤器Filter执行完后才会调用目标servlet实例的service()方法,并不是说调用目标servlet实例时,这组Filter的逻辑都执行完了,而是说他们都已经被调用起来之后才会最终调用servlet实例。
事实上,一个Filter可以被设计成既可以在目标servlet执行之前执行一段逻辑,也可以在目标servlet执行之后再执行另外一段逻辑。因此,在一个ApplicationFilterChain链执行到目标servlet实例的service()方法时,你可以认为此时所有Filter被设计在servlet执行之前执行的逻辑都执行完了,而所有Filter的被设计在servlet执行之后执行的逻辑都还尚未执行。
源代码分析
/* * 此源代码摘自Tomcat版本 8.5.23 */ package org.apache.catalina.core; import java.io.IOException; import java.security.Principal; import java.security.PrivilegedActionException; import java.util.Set; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Globals; import org.apache.catalina.security.SecurityUtil; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Implementation of javax.servlet.FilterChain used to manage * the execution of a set of filters for a particular request. When the * set of defined filters has all been executed, the next call to * doFilter() will execute the servlet's service() * method itself. * * @author Craig R. McClanahan */ public final class ApplicationFilterChain implements FilterChain { // Used to enforce requirements of SRV.8.2 / SRV.14.2.5.1 private 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; } } // -------------------------------------------------------------- Constants public 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 service() method of the servlet itself. * 执行过滤器链中的下一个过滤器Filter。如果链中所有过滤 4000 器都执行过, * 则调用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 */ @Override public 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>() { @Override public 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; else throw 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 one if (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 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); } } } /** * 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个, // 这个行为的结果是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()); } } } }
相关文章推荐
- How Tomcat works之第十一章之ApplicationFilterChain
- How Tomcat works之第十一章之ApplicationFilterChain
- Spring Security Web Application 之 Security Filter Chain
- tomcat责任链设计模式 FilterChain原理解析
- 知识库--ApplicationFilterChain(54)
- Spring Security Filter Chain Registration Using WebApplicationInitializer for Servlet 3.x
- spring security的springSecurityFilterChain怎么初始化的
- TomCat之Filter小析
- Shiro-1.2.2内置的FilterChain
- spring boot shiro结合使用,资源资源加载不到问题(filterchain的问题 ) 3ff8
- Spring 3 MVC Framework Based Hello World Web Application Example Using Maven, Eclipse IDE And Tomcat
- java模拟Filter,FilterChain的实现
- Filter及FilterChain的使用详解
- 启动tomcat时,一直卡在Deploying web application directory这块的解决方案
- spring security filter chain
- 利用Application.AddMessageFilter屏蔽消息
- 由Illegal access: this web application instance has been stopped already. 引出的tomcat配置问题
- Tomcat遇到”Error listenerStart”或”Error filterStart”问题且无详细日志时的log配置.
- tomcat异常:Illegal access: this web application instance has been stopped already. Could not load ...
- Tomcat遇到”Error listenerStart”或”Error filterStart”问题且无详细日志时的log配置