• How Tomcat Works(八)


    下面接着分析Context容器,该接口最重要的方法是addWrapper()方法与creatWrapper()方法,添加具体的子容器,这里是Wrapper容器实例

    这里要分析的是一个简单的Context容器,它针对特定的客户端请求,通过映射器找到要处理该特定请求的子容器实例(Wrapper)

    具体流程是,Context容器首先调用额外的阀,最后调用基础阀(这里是SimpleContextValve),在基础阀里面通过映射器找到要 处理该请求的子容器Wrapper实例,然后再调用子容器Wrapper实例的各个阀(本示例的Wrapper只有基础阀)(类似于composte模式 迭代)

    下面是SimpleContext类的实现,SimpleContext实现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;
        // 映射器协议与映射器实例映射
        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);
            }
        }    
    
        /**
         * 根据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);
        }
    
        /**
         * 根据名称查找子容器实例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));
            }
        }
    
        /**
         * 查找子容器数组
         * @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;
            }
        }
    
        /**
         * 根据协议查找映射器实例
         * @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;
        }
    
        /**
         * 根据请求找到子容器实例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
            // 具体过程 (回调该对象下面方法)
            // 根据request找到处理该请求的子容器wrapper名称 调用方法 String findServletMapping(String pattern)
            // 根据上面的子容器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的实现

    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)

    即根据客户端请求找到对应的子容器实例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系本人原创 

    转载请注明出处 博客园 刺猬的温驯 

    本人邮箱: chenying998179#163.com (#改为@

    本文链接 http://www.cnblogs.com/chenying99/p/3235730.html

  • 相关阅读:
    freemarker list集合去重,实现hashset
    freemarker特殊字符输出
    idea java 注释模板配置
    IntelliJ IDEA使用eclipse compiler(ecj)解决lombok编译问题
    odoo views
    python 内置函数 3.6版本
    iostat
    性能及优化之 vmstat
    python 基础
    git
  • 原文地址:https://www.cnblogs.com/chenying99/p/3235730.html
Copyright © 2020-2023  润新知