下面接著分析Context容器,該接口最重要的方法是addWrapper()方法與creatWrapper()方法,添加具體的子容器,這里是Wrapper容器實例
這里要分析的是一個簡單的Context容器,它針對特定的客戶端請求,通過映射器找到要處理該特定請求的子容器實例(Wrapper)
具體流程是,Context容器首先調用額外的閥,最后調用基礎閥(這里是SimpleContextValve),在基礎閥里面通過映射器找到要 處理該請求的子容器Wrapper實例,然后再調用子容器Wrapper實例的各個閥(本示例的Wrapper只有基礎閥)(類似于composte模式 迭代)
下面是SimpleContext類的實現(xiàn),SimpleContext實現(xiàn)org.apache.catalina.Context接口和org.apache.catalina.Pipeline接口
public class SimpleContext implements Context, Pipeline { public SimpleContext() { pipeline.setBasic( new SimpleContextValve()); } // 子容器名稱與子容器實例映射 protected HashMap children = new HashMap(); protected Loader loader = null ; protected SimplePipeline pipeline = new SimplePipeline( this ); // servlet模式與子容器名稱映射 protected HashMap servletMappings = new HashMap(); // 映射器 protected Mapper mapper = null ; // 映射器協(xié)議與映射器實例映射 protected HashMap mappers = new HashMap(); private Container parent = null ; /** * 添加servlet模式與子容器名稱(wrapper)到HashMap servletMappings容器 * @param pattern * @param name */ public void addServletMapping(String pattern, String name) { synchronized (servletMappings) { servletMappings.put(pattern, name); } } /** * 根據(jù)servlet模式找到對應的子容器名稱(wrapper)(供映射器調用) * @param pattern * @return */ public String findServletMapping(String pattern) { synchronized (servletMappings) { return ((String) servletMappings.get(pattern)); } } /** * 獲取加載器 * @return */ public Loader getLoader() { if (loader != null ) return (loader); if (parent != null ) return (parent.getLoader()); return ( null ); } /** * 設置加載器 * @param loader */ public void setLoader(Loader loader) { this .loader = loader; } /** * 添加子容器實例(wrapper)名稱與子容器實例(wrapper)到HashMap children容器 * @param child */ public void addChild(Container child) { child.setParent((Container) this ); children.put(child.getName(), child); } /** * 根據(jù)名稱查找子容器實例wrapper(供映射器調用) * @param name * @return */ public Container findChild(String name) { if (name == null ) return ( null ); synchronized (children) { // Required by post-start changes return ((Container) children.get(name)); } } /** * 查找子容器數(shù)組 * @return */ public Container[] findChildren() { synchronized (children) { Container results[] = new Container[children.size()]; return ((Container[]) children.values().toArray(results)); } } /** * 添加映射器實例 * @param mapper */ public void addMapper(Mapper mapper) { // this method is adopted from addMapper in ContainerBase // the first mapper added becomes the default mapper mapper.setContainer((Container) this ); // May throw IAE this .mapper = mapper; synchronized (mappers) { if (mappers.get(mapper.getProtocol()) != null ) throw new IllegalArgumentException("addMapper: Protocol '" + mapper.getProtocol() + "' is not unique" ); mapper.setContainer((Container) this ); // May throw IAE mappers.put(mapper.getProtocol(), mapper); if (mappers.size() == 1 ) this .mapper = mapper; else this .mapper = null ; } } /** * 根據(jù)協(xié)議查找映射器實例 * @param protocol * @return */ public Mapper findMapper(String protocol) { // the default mapper will always be returned, if any, // regardless the value of protocol if (mapper != null ) return (mapper); else synchronized (mappers) { return ((Mapper) mappers.get(protocol)); } } public Mapper[] findMappers() { return null ; } /** * 根據(jù)請求找到子容器實例wrapper (供基礎閥調用該方法) * @param request * @param update * @return */ public Container map(Request request, boolean update) { // this method is taken from the map method in // org.apache.cataline.core.ContainerBase // the findMapper method always returns the default mapper, if any, // regardless the // request's protocol Mapper mapper = findMapper(request.getRequest().getProtocol()); if (mapper == null ) return ( null ); // Use this Mapper to perform this mapping // 具體過程 (回調該對象下面方法) // 根據(jù)request找到處理該請求的子容器wrapper名稱 調用方法 String findServletMapping(String pattern) // 根據(jù)上面的子容器wrapper名稱找到子容器wrapper 調用方法 Container findChild(String name) return (mapper.map(request, update)); } public void invoke(Request request, Response response) throws IOException, ServletException { pipeline.invoke(request, response); } // method implementations of Pipeline public Valve getBasic() { return pipeline.getBasic(); } public void setBasic(Valve valve) { pipeline.setBasic(valve); } public synchronized void addValve(Valve valve) { pipeline.addValve(valve); } public Valve[] getValves() { return pipeline.getValves(); } public void removeValve(Valve valve) { pipeline.removeValve(valve); } }
下面我們來分析映射器SimpleContextMapper的實現(xiàn)
public class SimpleContextMapper implements Mapper { /** * The Container with which this Mapper is associated. */ private SimpleContext context = null ; public Container getContainer() { return (context); } public void setContainer(Container container) { if (!(container instanceof SimpleContext)) throw new IllegalArgumentException ( "Illegal type of container" ); context = (SimpleContext) container; } public String getProtocol() { return null ; } public void setProtocol(String protocol) { } /** * Return the child Container that should be used to process this Request, * based upon its characteristics. If no such child Container can be * identified, return <code>null</code> instead. * * @param request Request being processed * @param update Update the Request to reflect the mapping selection? * * @exception IllegalArgumentException if the relative portion of the * path cannot be URL decoded */ public Container map(Request request, boolean update) { // Identify the context-relative URI to be mapped String contextPath = ((HttpServletRequest) request.getRequest()).getContextPath(); String requestURI = ((HttpRequest) request).getDecodedRequestURI(); String relativeURI = requestURI.substring(contextPath.length()); // Apply the standard request URI mapping rules from the specification Wrapper wrapper = null ; String servletPath = relativeURI; String pathInfo = null ; String name = context.findServletMapping(relativeURI); if (name != null ) wrapper = (Wrapper) context.findChild(name); return (wrapper); } }
映射器SimpleContextMapper最重要的方法是Container map(Request request, boolean update)
即根據(jù)客戶端請求找到對應的子容器實例wrapper,里面關鍵代碼是回調context容器實例的方法(持有對SimpleContext實例的引用)
接下里分析基礎閥的關鍵代碼(管道持有對基礎閥的引用)
public class SimpleContextValve implements Valve, Contained { protected Container container; public void invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException { // Validate the request and response object types if (!(request.getRequest() instanceof HttpServletRequest) || !(response.getResponse() instanceof HttpServletResponse)) { return ; // NOTE - Not much else we can do generically } // Disallow any direct access to resources under WEB-INF or META-INF HttpServletRequest hreq = (HttpServletRequest) request.getRequest(); String contextPath = hreq.getContextPath(); String requestURI = ((HttpRequest) request).getDecodedRequestURI(); String relativeURI = requestURI.substring(contextPath.length()).toUpperCase(); Context context = (Context) getContainer(); // Select the Wrapper to be used for this Request Wrapper wrapper = null ; try { wrapper = (Wrapper) context.map(request, true ); } catch (IllegalArgumentException e) { badRequest(requestURI, (HttpServletResponse) response.getResponse()); return ; } if (wrapper == null ) { notFound(requestURI, (HttpServletResponse) response.getResponse()); return ; } // Ask this Wrapper to process this Request response.setContext(context); wrapper.invoke(request, response); } public Container getContainer() { return container; } public void setContainer(Container container) { this .container = container; } private void badRequest(String requestURI, HttpServletResponse response) { try { response.sendError(HttpServletResponse.SC_BAD_REQUEST, requestURI); } catch (IllegalStateException e) { ; } catch (IOException e) { ; } } private void notFound(String requestURI, HttpServletResponse response) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND, requestURI); } catch (IllegalStateException e) { ; } catch (IOException e) { ; } } }
基礎閥持有對Context容器實例(SimpleContext)的引用,在它的關鍵方法void invoke(Request request, Response response, ValveContext valveContext)里面,先調用Context容器實例的Container map(Request request, boolean update)方法獲取子容器實例wrapper,最后調用子容器實例wrapper的invoke(Request request, Response response)方法
至于管道類SimplePipeline與上文相同,此處不再描述
---------------------------------------------------------------------------?
本系列How Tomcat Works系本人原創(chuàng)?
轉載請注明出處 博客園 刺猬的溫馴?
本人郵箱: chenying998179 # 163.com ( #改為@ )
更多文章、技術交流、商務合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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