博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
How Tomcat Works(七)
阅读量:7250 次
发布时间:2019-06-29

本文共 9647 字,大约阅读时间需要 32 分钟。

本文接下来介绍并分析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 (#改为@

本文链接

你可能感兴趣的文章
对比文件md5值实现去重文件
查看>>
C#设计模式之二十三解释器模式(Interpreter Pattern)【行为型】
查看>>
js处理中文乱码记录/nodejs+express error 413
查看>>
基于Keepalived实现LVS双主高可用集群
查看>>
SqlServer 使用脚本创建分发服务及事务复制的可更新订阅
查看>>
什么是Floating (浮动)规则?
查看>>
分布式文件系统-FastDFS
查看>>
HTML5 rotate 做仪表盘
查看>>
为什么说荆州松滋刘氏采穴堂是刘开七、刘广传的后裔
查看>>
React中使用Ant Table组件
查看>>
第四篇 快速、轻量、可扩展、易于使用的EmEditor
查看>>
MySQL删除小写记录
查看>>
用shell脚本收集查询IP信息的网站
查看>>
shiro整合oauth
查看>>
超级网管员——网络管理
查看>>
AjaxControltoolkit(工具包)安装步骤说明
查看>>
利用组策略进行的一次Windows主机安全整改
查看>>
Ruby语法学习笔记(1)
查看>>
Windows Phone 7 使用选择器(Chooser)
查看>>
QOS 之 WRED
查看>>