在 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類實現(xiàn)了該接口
ApplicationFilterChain類采用一個私有成員變量private ArrayList filters = new ArrayList()保存ApplicationFilterConfig對象的集合,ApplicationFilterConfig類實現(xiàn)了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類的實現(xiàn)FilterChain接口方法doFilter()中,調(diào)用了其私有方法internalDoFilter(),下面是該方法的具體實現(xiàn)
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); } }
在調(diào)用了filter.doFilter(request, response, this)方法之后,繼續(xù)執(zhí)行servlet的service()方法
這里的this是ApplicationFilterChain對象自身,在我們編寫的Filter實現(xiàn)類里面同在在執(zhí)行完我們實現(xiàn)的過濾方法之后會繼續(xù)調(diào)用FilterChain對象的void doFilter(ServletRequest request, ServletResponse response)方法,我們自定義的過濾器通常會這樣實現(xiàn):
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類實現(xiàn)了javax.servlet.FilterConfig接口,代表一個Filter容器,F(xiàn)ilterConfig接口定義如下:
public interface FilterConfig { public String getFilterName(); public ServletContext getServletContext(); public String getInitParameter(String name); public Enumeration getInitParameterNames(); }
可以通過傳入org.apache.catalina.Context對象和FilterDef對象(FilterDef對象用于對過濾器類的定義,包括過濾器類名、相關參數(shù)等)傳給其構造函數(shù)構造一個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); }
現(xiàn)在,也許我們更容易理解StandardWrapperValve類中創(chuàng)建過濾器鏈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系本人原創(chuàng)?
轉載請注明出處 博客園 刺猬的溫馴?
本人郵箱: ? chenying998179 # 163.com ( #改為@ )
更多文章、技術交流、商務合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
