How Tomcat Works(七)

系统 1614 0

本文接下来介绍并分析servlet容器,servlet容器是用来处理请求servlet资源,并为web客户端填充response对象的模块。

servlet容器是org.apache.catalina.Container接口的实例,在tomcat中,有四种类型的容器,分别为Engine、Host 、Context和Wrapper。

Engine. 代表整个容器的servlet引擎。
Host.代表一个拥有一定数量Context的虚拟主机。
Context.代表一个Web项目.一个Context包含一个或多个Wrapper。
Wrapper.代表单独的一个servlet。

这些容器构成一个自顶向下的等级结构,高等级的容器可以具有多个直接下属等级的容器实例(子容器),这有点类似于composite模式,不过还是有差别的

org.apache.catalina.Container接口声明如下

      
        //
      
      
        添加
      
      
        public
      
      
        void
      
      
         addChild(Container child);

      
      
        //
      
      
        删除
      
      
        public
      
      
        void
      
      
         removeChild(Container child);

      
      
        //
      
      
        查找
      
      
        public
      
      
         Container findChild(String name);

      
      
        //
      
      
        查找全部
      
      
        public
      
       Container[] findChildren();
    

上面方法均为操作子容器的相关方法

容器可以包含一些支持的组件,诸如载入器、记录器、管理器、领域和资源等,我们可以通过编辑server.xml文件来决定使用哪种容器。

下面我们来分析servlet容器是怎么执行任务的,这里就要提到servlet容器的管道模型,管道包含了该servlet容器将要调用的任务,而阀则表示一个具体的执行任务;在servlet容器的管道中,有一个基础阀,也可以添加任意数量的额外阀,阀的数量通常是指额外添加的阀的数量,不包括基础阀

这里就好像servlet编程中的过滤器模型,管道好比过滤器链,而阀则是具体的过滤器;基础阀总是最后一个执行的。

这里涉及几个相关的接口,包括Pipeline、Valve、ValveContext 和Contained

Pipeline接口声明如下

      
        public
      
      
        interface
      
      
         Pipeline {
   
      
      
        public
      
      
         Valve getBasic();

      
      
        public
      
      
        void
      
      
         setBasic(Valve valve);
    
      
      
        public
      
      
        void
      
      
         addValve(Valve valve);
   
      
      
        public
      
      
         Valve[] getValves();
   
      
      
        public
      
      
        void
      
      
         invoke(Request request, Response response)
        
      
      
        throws
      
      
         IOException, ServletException;
   
      
      
        public
      
      
        void
      
      
         removeValve(Valve valve);

}
      
    

Valve接口声明如下

      
        public
      
      
        interface
      
      
         Valve {
        
public String getInfo(); public void invoke(Request request, Response response, ValveContext context) throws IOException, ServletException; }

ValveContext接口声明

      
        public
      
      
        interface
      
      
         ValveContext {
  
      
      
        public
      
      
         String getInfo();
   
      
      
        public
      
      
        void
      
      
         invokeNext(Request request, Response response)
        
      
      
        throws
      
      
         IOException, ServletException;
}
      
    

Contained接口声明

      
        public
      
      
        interface
      
      
         Contained {
    
      
      
        public
      
      
         Container getContainer();
   
      
      
        public
      
      
        void
      
      
         setContainer(Container container);

}
      
    

阀可以选择是否实现该接口,设置阀与一个servlet容器相关连

下面我们来学习Wrapper容器,Wrapper容器表示一个独立的servlet定义,负责管理其基础servlet类的生命周期,它继承了Container接口,另外添加了额外方法声明。其中比较重要的方法声明是load()方法和allocate()方法,均与载入及初始化servlet类相关(供基础阀调用,基础阀持有Wrapper容器实例引用)

下面来分析一个简单的Wrapper类,该类实现了org.apache.catalina.Wrapper接口和org.apache.catalina.Pipeline接口

      
        public
      
      
        class
      
       SimpleWrapper 
      
        implements
      
      
         Wrapper, Pipeline {

  
      
      
        //
      
      
         the servlet instance
      
      
        private
      
       Servlet instance = 
      
        null
      
      
        ;
  
      
      
        private
      
      
         String servletClass;
  
      
      
        private
      
      
         Loader loader; 
      
      
        private
      
       SimplePipeline pipeline = 
      
        new
      
       SimplePipeline(
      
        this
      
      
        );
  
      
      
        protected
      
       Container parent = 
      
        null
      
      
        ;

  
      
      
        public
      
      
         SimpleWrapper() {
    pipeline.setBasic(
      
      
        new
      
      
         SimpleWrapperValve());
  }

  
      
      
        public
      
      
        synchronized
      
      
        void
      
      
         addValve(Valve valve) {
    pipeline.addValve(valve);
  }

  
      
      
        public
      
       Servlet allocate() 
      
        throws
      
      
         ServletException {
    
      
      
        //
      
      
         Load and initialize our instance if necessary
      
      
        if
      
       (instance==
      
        null
      
      
        ) {
      
      
      
        try
      
      
         {
        instance 
      
      =
      
         loadServlet();
      }
      
      
      
        catch
      
      
         (ServletException e) {
        
      
      
        throw
      
      
         e;
      }
      
      
      
        catch
      
      
         (Throwable e) {
        
      
      
        throw
      
      
        new
      
       ServletException("Cannot allocate a servlet instance"
      
        , e);
      }
    }
    
      
      
        return
      
      
         instance;
  }

  
      
      
        private
      
       Servlet loadServlet() 
      
        throws
      
      
         ServletException {
    
      
      
        if
      
       (instance!=
      
        null
      
      
        )
      
      
      
        return
      
      
         instance;

    Servlet servlet 
      
      = 
      
        null
      
      
        ;
    String actualClass 
      
      =
      
         servletClass;
    
      
      
        if
      
       (actualClass == 
      
        null
      
      
        ) {
      
      
      
        throw
      
      
        new
      
       ServletException("servlet class has not been specified"
      
        );
    }

    Loader loader 
      
      =
      
         getLoader();
    
      
      
        //
      
      
         Acquire an instance of the class loader to be used
      
      
        if
      
       (loader==
      
        null
      
      
        ) {
      
      
      
        throw
      
      
        new
      
       ServletException("No loader."
      
        );
    }
    ClassLoader classLoader 
      
      =
      
         loader.getClassLoader();

    
      
      
        //
      
      
         Load the specified servlet class from the appropriate class loader
      
      
    Class classClass = 
      
        null
      
      
        ;
    
      
      
        try
      
      
         {
      
      
      
        if
      
       (classLoader!=
      
        null
      
      
        ) {
        classClass 
      
      =
      
         classLoader.loadClass(actualClass);
      }
    }
    
      
      
        catch
      
      
         (ClassNotFoundException e) {
      
      
      
        throw
      
      
        new
      
       ServletException("Servlet class not found"
      
        );
    }
    
      
      
        //
      
      
         Instantiate and initialize an instance of the servlet class itself
      
      
        try
      
      
         {
      servlet 
      
      =
      
         (Servlet) classClass.newInstance();
    }
    
      
      
        catch
      
      
         (Throwable e) {
      
      
      
        throw
      
      
        new
      
       ServletException("Failed to instantiate servlet"
      
        );
    }

    
      
      
        //
      
      
         Call the initialization method of this servlet
      
      
        try
      
      
         {
      servlet.init(
      
      
        null
      
      
        );
    }
    
      
      
        catch
      
      
         (Throwable f) {
      
      
      
        throw
      
      
        new
      
       ServletException("Failed initialize servlet."
      
        );
    }
    
      
      
        return
      
      
         servlet;
  }  
      
      
        public
      
      
         Loader getLoader() {
    
      
      
        if
      
       (loader != 
      
        null
      
      
        )
      
      
      
        return
      
      
         (loader);
    
      
      
        if
      
       (parent != 
      
        null
      
      
        )
      
      
      
        return
      
      
         (parent.getLoader());
    
      
      
        return
      
       (
      
        null
      
      
        );
  }
      
      
        public
      
      
        void
      
      
         invoke(Request request, Response response)
    
      
      
        throws
      
      
         IOException, ServletException {
    pipeline.invoke(request, response);
  }  
      
      
        public
      
      
        void
      
       load() 
      
        throws
      
      
         ServletException {
    instance 
      
      =
      
         loadServlet();
  }
        
// method implementations of Pipeline public Valve getBasic() { return pipeline.getBasic(); } public void setBasic(Valve valve) { pipeline.setBasic(valve); } public Valve[] getValves() { return pipeline.getValves(); } public void removeValve(Valve valve) { pipeline.removeValve(valve); } }

上面的SimpleWrapper类由于实现了org.apache.catalina.Pipeline接口接口,同时与该接口相关的实现方法都是调用引用的成员变量SimplePipeline pipeline = new SimplePipeline(this)的对应方法,因此我们可以理解为SimpleWrapper类为SimplePipeline的包装类

在它的invoke()方法里面调用了成员变量的SimplePipeline pipeline = new SimplePipeline(this)的invoke()方法,这里构造函数传入SimpleWrapper实例本身,可以猜想是为了获取其载入器及具体的servlet实现类(注:该方法为Container接口与Pipeline接口都具有的方法声明,因此SimpleWrapper类只要一个实现),下面我们继续分析SimplePipeline相关实现

      
        public
      
      
        class
      
       SimplePipeline 
      
        implements
      
      
         Pipeline {

  
      
      
        public
      
      
         SimplePipeline(Container container) {
    setContainer(container);
  }

  
      
      
        //
      
      
         The basic Valve (if any) associated with this Pipeline.
      
      
        protected
      
       Valve basic = 
      
        null
      
      
        ;
  
      
      
        //
      
      
         The Container with which this Pipeline is associated.
      
      
        protected
      
       Container container = 
      
        null
      
      
        ;
  
      
      
        //
      
      
         the array of Valves
      
      
        protected
      
       Valve valves[] = 
      
        new
      
       Valve[0
      
        ];

  
      
      
        public
      
      
        void
      
      
         setContainer(Container container) {
    
      
      
        this
      
      .container =
      
         container;
  }

  
      
      
        public
      
      
         Valve getBasic() {
    
      
      
        return
      
      
         basic;
  }

  
      
      
        public
      
      
        void
      
      
         setBasic(Valve valve) {
    
      
      
        this
      
      .basic =
      
         valve;
    ((Contained) valve).setContainer(container);
  }

  
      
      
        public
      
      
        void
      
      
         addValve(Valve valve) {
    
      
      
        if
      
       (valve 
      
        instanceof
      
      
         Contained)
      ((Contained) valve).setContainer(
      
      
        this
      
      
        .container);

    
      
      
        synchronized
      
      
         (valves) {
      Valve results[] 
      
      = 
      
        new
      
       Valve[valves.length +1
      
        ];
      System.arraycopy(valves, 
      
      0, results, 0
      
        , valves.length);
      results[valves.length] 
      
      =
      
         valve;
      valves 
      
      =
      
         results;
    }
  }

  
      
      
        public
      
      
         Valve[] getValves() {
    
      
      
        return
      
      
         valves;
  }

  
      
      
        public
      
      
        void
      
      
         invoke(Request request, Response response)
    
      
      
        throws
      
      
         IOException, ServletException {
    
      
      
        //
      
      
         Invoke the first Valve in this pipeline for this request
      
      
    (
      
        new
      
      
         SimplePipelineValveContext()).invokeNext(request, response);
  }

  
      
      
        public
      
      
        void
      
      
         removeValve(Valve valve) {
  }

  
      
      
        //
      
      
         this class is copied from org.apache.catalina.core.StandardPipeline class's
  
      
      
        //
      
      
         StandardPipelineValveContext inner class.
      
      
        protected
      
      
        class
      
       SimplePipelineValveContext 
      
        implements
      
      
         ValveContext {

    
      
      
        protected
      
      
        int
      
       stage = 0
      
        ;

    
      
      
        public
      
      
         String getInfo() {
      
      
      
        return
      
      
        null
      
      
        ;
    }

    
      
      
        public
      
      
        void
      
      
         invokeNext(Request request, Response response)
      
      
      
        throws
      
      
         IOException, ServletException {
      
      
      
        int
      
       subscript =
      
         stage;
      stage 
      
      = stage + 1
      
        ;
      
      
      
        //
      
      
         Invoke the requested Valve for the current request thread
      
      
        if
      
       (subscript <
      
         valves.length) {
        valves[subscript].invoke(request, response, 
      
      
        this
      
      
        );
      }
      
      
      
        else
      
      
        if
      
       ((subscript == valves.length) && (basic != 
      
        null
      
      
        )) {
        basic.invoke(request, response, 
      
      
        this
      
      
        );
      }
      
      
      
        else
      
      
         {
        
      
      
        throw
      
      
        new
      
       ServletException("No valve"
      
        );
      }
    }
  } 
      
      
        //
      
      
         end of inner class
      
      
        
}
      
    

invoke()方法里面调用内部类SimplePipelineValveContext(实现了ValveContext接口),遍历执行各个阀的invoke()方法

wrapper容器执行的基本流程如上所述,下面我们来进一步分析相关辅助类及实现类等

在应用初始化servlet容器时,我们需要为其指定一个载入器,下面是一个简单的载入器,实现了Loader接口

      
        public
      
      
        class
      
       SimpleLoader 
      
        implements
      
      
         Loader {

  
      
      
        public
      
      
        static
      
      
        final
      
       String WEB_ROOT =
      
        
    System.getProperty(
      
      "user.dir") + File.separator  + "webroot"
      
        ;

  ClassLoader classLoader 
      
      = 
      
        null
      
      
        ;
  Container container 
      
      = 
      
        null
      
      
        ;

  
      
      
        public
      
      
         SimpleLoader() {
    
      
      
        try
      
      
         {
      URL[] urls 
      
      = 
      
        new
      
       URL[1
      
        ];
      URLStreamHandler streamHandler 
      
      = 
      
        null
      
      
        ;
      File classPath 
      
      = 
      
        new
      
      
         File(WEB_ROOT);
      String repository 
      
      = (
      
        new
      
       URL("file", 
      
        null
      
      , classPath.getCanonicalPath() +
      
         File.separator)).toString() ;
      urls[
      
      0] = 
      
        new
      
       URL(
      
        null
      
      
        , repository, streamHandler);
      classLoader 
      
      = 
      
        new
      
      
         URLClassLoader(urls);
    }
    
      
      
        catch
      
      
         (IOException e) {
      System.out.println(e.toString() );
    }


  }

  
      
      
        public
      
      
         ClassLoader getClassLoader() {
    
      
      
        return
      
      
         classLoader;
  }

  
      
      
        public
      
      
         Container getContainer() {
    
      
      
        return
      
      
         container;
  }
   
      
      
        //
      
      
        这里省略其余代码
      
      
}
    

基础阀是干嘛的呢,具体来说是调用具体servlet的service()方法(管道持有对基础阀的引用)

      
        public
      
      
        class
      
       SimpleWrapperValve 
      
        implements
      
      
         Valve, Contained {

  
      
      
        protected
      
      
         Container container;

  
      
      
        public
      
      
        void
      
      
         invoke(Request request, Response response, ValveContext valveContext)
    
      
      
        throws
      
      
         IOException, ServletException {

    SimpleWrapper wrapper 
      
      =
      
         (SimpleWrapper) getContainer();
    ServletRequest sreq 
      
      =
      
         request.getRequest();
    ServletResponse sres 
      
      =
      
         response.getResponse();
    Servlet servlet 
      
      = 
      
        null
      
      
        ;
    HttpServletRequest hreq 
      
      = 
      
        null
      
      
        ;
    
      
      
        if
      
       (sreq 
      
        instanceof
      
      
         HttpServletRequest)
      hreq 
      
      =
      
         (HttpServletRequest) sreq;
    HttpServletResponse hres 
      
      = 
      
        null
      
      
        ;
    
      
      
        if
      
       (sres 
      
        instanceof
      
      
         HttpServletResponse)
      hres 
      
      =
      
         (HttpServletResponse) sres;

    
      
      
        //
      
      
         Allocate a servlet instance to process this request
      
      
        try
      
      
         {
      servlet 
      
      =
      
         wrapper.allocate();
      
      
      
        if
      
       (hres!=
      
        null
      
       && hreq!=
      
        null
      
      
        ) {
        servlet.service(hreq, hres);
      }
      
      
      
        else
      
      
         {
        servlet.service(sreq, sres);
      }
    }
    
      
      
        catch
      
      
         (ServletException e) {
    }
  }

  
      
      
        public
      
      
         String getInfo() {
    
      
      
        return
      
      
        null
      
      
        ;
  }

  
      
      
        public
      
      
         Container getContainer() {
    
      
      
        return
      
      
         container;
  }

  
      
      
        public
      
      
        void
      
      
         setContainer(Container container) {
    
      
      
        this
      
      .container =
      
         container;
  }
}
      
    

其他额外添加的阀本人就不在具体描述了,至此SimpleWrapper容器分析完毕!

--------------------------------------------------------------------------- 

本系列How Tomcat Works系本人原创 

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

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

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

How Tomcat Works(七)


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

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

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

【本文对您有帮助就好】

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

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