在How Tomcat Works(十四)中,本人并没有对javax.servlet.Filter及javax.servlet.FilterChain做详细的描述,本文在这里做一下补充
FilterChain接口只有一个方法,方法声明如下:
public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;
在tomcat中,org.apache.catalina.core.ApplicationFilterChain类实现了该接口
ApplicationFilterChain类采用一个私有成员变量private ArrayList filters = new ArrayList()保存ApplicationFilterConfig对象的集合,ApplicationFilterConfig类实现了javax.servlet.FilterConfig接口,封装了对Filter实例的管理
下面是向ArrayList filters集合添加ApplicationFilterConfig实例
void addFilter(ApplicationFilterConfig filterConfig) { this.filters.add(filterConfig); }
setServlet()方法用于向ApplicationFilterChain对象设置当前的servlet实例
void setServlet(Servlet servlet) { this.servlet = servlet; }
在ApplicationFilterChain类的实现FilterChain接口方法doFilter()中,调用了其私有方法internalDoFilter(),下面是该方法的具体实现
private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // Construct an iterator the first time this method is called if (this.iterator == null) this.iterator = filters.iterator(); // Call the next filter if there is one if (this.iterator.hasNext()) { ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) iterator.next(); Filter filter = null; try { filter = filterConfig.getFilter(); support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT, filter, request, response); filter.doFilter(request, response, this); support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response); } catch (IOException e) { if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response, e); throw e; } catch (ServletException e) { if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response, e); throw e; } catch (RuntimeException e) { if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response, e); throw e; } catch (Throwable e) { if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response, e); throw new ServletException (sm.getString("filterChain.filter"), e); } return; } // We fell off the end of the chain -- call the servlet instance try { support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT, servlet, request, response); if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse)) { servlet.service((HttpServletRequest) request, (HttpServletResponse) response); } else { servlet.service(request, response); } support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response); } catch (IOException e) { support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); throw e; } catch (ServletException e) { support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); throw e; } catch (RuntimeException e) { support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); throw e; } catch (Throwable e) { support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); throw new ServletException (sm.getString("filterChain.servlet"), e); } }
在调用了filter.doFilter(request, response, this)方法之后,继续执行servlet的service()方法
这里的this是ApplicationFilterChain对象自身,在我们编写的Filter实现类里面同在在执行完我们实现的过滤方法之后会继续调用FilterChain对象的void doFilter(ServletRequest request, ServletResponse response)方法,我们自定义的过滤器通常会这样实现:
class SampleFilter implements Filter { ........ public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException { //do something ..... //request, response传递给下一个过滤器进行过滤 chain.doFilter(request, response); } }
ApplicationFilterConfig类实现了javax.servlet.FilterConfig接口,代表一个Filter容器,FilterConfig接口定义如下:
public interface FilterConfig { public String getFilterName(); public ServletContext getServletContext(); public String getInitParameter(String name); public Enumeration getInitParameterNames(); }
可以通过传入org.apache.catalina.Context对象和FilterDef对象(FilterDef对象用于对过滤器类的定义,包括过滤器类名、相关参数等)传给其构造函数构造一个ApplicationFilterConfig对象:
public ApplicationFilterConfig(Context context, FilterDef filterDef) throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException { super(); this.context = context; setFilterDef(filterDef); }
ApplicationFilterConfig类的getFilter()方法返回一个javax.servlet.Filter对象,该方法负责载入并实例化一个过滤器类
Filter getFilter() throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException { // Return the existing filter instance, if any if (this.filter != null) return (this.filter); // Identify the class loader we will be using String filterClass = filterDef.getFilterClass(); ClassLoader classLoader = null; if (filterClass.startsWith("org.apache.catalina.")) classLoader = this.getClass().getClassLoader(); else classLoader = context.getLoader().getClassLoader(); ClassLoader oldCtxClassLoader = Thread.currentThread().getContextClassLoader(); // Instantiate a new instance of this filter and return it Class clazz = classLoader.loadClass(filterClass); this.filter = (Filter) clazz.newInstance(); filter.init(this); return (this.filter); }
现在,也许我们更容易理解StandardWrapperValve类中创建过滤器链createFilterChain()方法了
private ApplicationFilterChain createFilterChain(Request request, Servlet servlet) { // If there is no servlet to execute, return null if (servlet == null) return (null); // Create and initialize a filter chain object ApplicationFilterChain filterChain = new ApplicationFilterChain(); filterChain.setServlet(servlet); StandardWrapper wrapper = (StandardWrapper) getContainer(); filterChain.setSupport(wrapper.getInstanceSupport()); // Acquire the filter mappings for this Context StandardContext context = (StandardContext) wrapper.getParent(); FilterMap filterMaps[] = context.findFilterMaps(); // If there are no filter mappings, we are done if ((filterMaps == null) || (filterMaps.length == 0)) return (filterChain); // if (debug >= 1) // log("createFilterChain: Processing " + filterMaps.length + // " filter map entries"); // Acquire the information we will need to match filter mappings String requestPath = null; if (request instanceof HttpRequest) { HttpServletRequest hreq = (HttpServletRequest) request.getRequest(); String contextPath = hreq.getContextPath(); if (contextPath == null) contextPath = ""; String requestURI = ((HttpRequest) request).getDecodedRequestURI(); if (requestURI.length() >= contextPath.length()) requestPath = requestURI.substring(contextPath.length()); } String servletName = wrapper.getName(); // if (debug >= 1) { // log(" requestPath=" + requestPath); // log(" servletName=" + servletName); // } int n = 0; // Add the relevant path-mapped filters to this filter chain for (int i = 0; i < filterMaps.length; i++) { // if (debug >= 2) // log(" Checking path-mapped filter '" + // filterMaps[i] + "'"); if (!matchFiltersURL(filterMaps[i], requestPath)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); if (filterConfig == null) { // if (debug >= 2) // log(" Missing path-mapped filter '" + // filterMaps[i] + "'"); ; // FIXME - log configuration problem continue; } // if (debug >= 2) // log(" Adding path-mapped filter '" + // filterConfig.getFilterName() + "'"); filterChain.addFilter(filterConfig); n++; } // Add filters that match on servlet name second for (int i = 0; i < filterMaps.length; i++) { // if (debug >= 2) // log(" Checking servlet-mapped filter '" + // filterMaps[i] + "'"); if (!matchFiltersServlet(filterMaps[i], servletName)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); if (filterConfig == null) { // if (debug >= 2) // log(" Missing servlet-mapped filter '" + // filterMaps[i] + "'"); ; // FIXME - log configuration problem continue; } // if (debug >= 2) // log(" Adding servlet-mapped filter '" + // filterMaps[i] + "'"); filterChain.addFilter(filterConfig); n++; } // Return the completed filter chain // if (debug >= 2) // log(" Returning chain with " + n + " filters"); return (filterChain); }
---------------------------------------------------------------------------
本系列How Tomcat Works系本人原创
转载请注明出处 博客园 刺猬的温驯
本人邮箱: chenying998179#163.com (#改为@)