How Tomcat Works(八)
下面接著分析Context容器,該接口最重要的方法是addWrapper()方法與creatWrapper()方法,添加具體的子容器,這里是Wrapper容器實例
這里要分析的是一個簡單的Context容器,它針對特定的客戶端請求,通過映射器找到要處理該特定請求的子容器實例(Wrapper)
具體流程是,Context容器首先調(diào)用額外的閥,最后調(diào)用基礎(chǔ)閥(這里是SimpleContextValve),在基礎(chǔ)閥里面通過映射器找到要 處理該請求的子容器Wrapper實例,然后再調(diào)用子容器Wrapper實例的各個閥(本示例的Wrapper只有基礎(chǔ)閥)(類似于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模式找到對應(yīng)的子容器名稱(wrapper)(供映射器調(diào)用)* @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);}/*** 設(shè)置加載器* @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(供映射器調(diào)用)* @param name* @return*/public Container findChild(String name) {if (name == null)return (null);synchronized (children) {// Required by post-start changesreturn ((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 mappermapper.setContainer((Container) this); // May throw IAEthis.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;elsethis.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 protocolif (mapper != null)return (mapper);elsesynchronized (mappers) {return ((Mapper) mappers.get(protocol));}}public Mapper[] findMappers() {return null;}/*** 根據(jù)請求找到子容器實例wrapper (供基礎(chǔ)閥調(diào)用該方法)* @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 protocolMapper mapper = findMapper(request.getRequest().getProtocol());if (mapper == null)return (null);// Use this Mapper to perform this mapping// 具體過程 (回調(diào)該對象下面方法)// 根據(jù)request找到處理該請求的子容器wrapper名稱 調(diào)用方法 String findServletMapping(String pattern)// 根據(jù)上面的子容器wrapper名稱找到子容器wrapper 調(diào)用方法 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 Pipelinepublic 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 mappedString 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 specificationWrapper 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ù)客戶端請求找到對應(yīng)的子容器實例wrapper,里面關(guān)鍵代碼是回調(diào)context容器實例的方法(持有對SimpleContext實例的引用)
接下里分析基礎(chǔ)閥的關(guān)鍵代碼(管道持有對基礎(chǔ)閥的引用)
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 typesif (!(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-INFHttpServletRequest 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 RequestWrapper 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) {;}}}基礎(chǔ)閥持有對Context容器實例(SimpleContext)的引用,在它的關(guān)鍵方法void invoke(Request request, Response response, ValveContext valveContext)里面,先調(diào)用Context容器實例的Container map(Request request, boolean update)方法獲取子容器實例wrapper,最后調(diào)用子容器實例wrapper的invoke(Request request, Response response)方法
至于管道類SimplePipeline與上文相同,此處不再描述
---------------------------------------------------------------------------?
本系列How Tomcat Works系本人原創(chuàng)?
轉(zhuǎn)載請注明出處 博客園 刺猬的溫馴?
本人郵箱: chenying998179#163.com (#改為@)
本文鏈接 http://www.cnblogs.com/chenying99/p/3235730.html
轉(zhuǎn)載于:https://www.cnblogs.com/chenying99/p/3235730.html
總結(jié)
以上是生活随笔為你收集整理的How Tomcat Works(八)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决J2EE系统应用性能问题常用方法
- 下一篇: 【ACM】nyoj_540_奇怪的排序_