How Tomcat Works(八)

系统 1641 0

下面接着分析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

How Tomcat Works(八)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论