`
he_wen
  • 浏览: 239508 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

《How Tomcat Works》翻译(3)之Context容器

阅读更多

一、The Context应用

    在这章的第一个应用程序(Wrapper容器),你已经学会了怎样部署一个仅仅只有一个wrapper容器的简单Web应用程序。这个程序只有一个servlet。尽管在一些应用程序中可能只需要仅仅一个servelt,但是大部分应用程序是需要多个servlet.因此在本应用程序中有增加了一个类型的容器(Context容器,它是Wrapper的父类容器)。

 

   本应用程序阐明了怎样用一个Context容器(该容器包含两个Wrapper容器即两个servlet类)。因此,你拥有了更多的Wrapper容器,就需要借助一个组件(Mapper),帮助容器(Context容器)选择一个要处理特定请求的Request的孩子容器(Wrapper容器)。

 

         注意:A Mapper组件出现在Tomcat4中,但是在Tomcat5中该组件移除了,引用了另外一种方式来查找孩子容器(Wrapper容器)。

       在本应用程序中,你的Mapper实例是ex05.pyrmont.core.SimpleContextMapper类,它实现了org.apache.catalina.Mapper接口(这是在Tomcat4)。一个容器也能够用多个mappers(为了支持不同种类的协议)。在本应用程序中一个mapper支持一个request协议。比如,一个容器可能一个mapper对应Http协议,而另外一个mapper对应了the Https协议。下面代码是Tomcat4提供的Mapper接口:

 

package org.apache.catalina;

public interface Mapper {
    public Container getContainer();
    public void setContainer(Container container);
    public String getProtocol();
    public void setProtocol(String protocol);
    public Container map(Request request, boolean update);


}

 The getContainer方法返回就是容器与mapper相关联,The setContainer方法就是设置the mapper与 the Container相关联。The getProtocol方法返回the mapper负责处理的协议,setProtocol方法就是把协议的名称赋给负责处理协议的the mapper.The map方法返回一个将要处理特定请求的孩子容器。

         下面是本应用程序的类图:



    注解:一定要把类图和下面的一段看明白,才能够真正的理解父容器和孩子容器之间的关系和设计者的思路,这个十分重要。他们是借助the mapper组件来进行联系。。。

     The SimpleContext代表一个Context容器,The SimpleContextMapper作为mapper组件,the SimpleContextValve作为一个basic valve.两个Valve分别是:ClientIPLogger、HeaderLoggerValve全部添加到The Context容器。两个Wrapper(都是由SimpleWrapper组成)被添加到The COntext容器里(就是作为它的孩子容器)。The wrappers使用SimpleWrapperValve作为他们的basic valve但是没有添加其他的valves.

      The Context 应用程序使用了上个应用程序一样的的Loader和两个Valves。然而,The Loader和Valves是与the Context容器相关联而不是与Wrapper容器相关。注解:理解这里十分重要。因此

the Loader能够被两个Wrapper容器公用。The Context被赋给了The connector。因此,只要The Connector接收到一个Http请求,它就会调用the Context的invoke方法。如果你已经对上个程序已经领悟到了其中的精髓,那么剩下的调用关系就很容易理解了。

      1、一个Container要有一个pipeline.The Container的Invoke方法就会调用the pipeline的Invoke方法。

      2、The pipeline的Invoke方法就会调用添加整个Container的所有Valve中的Invoke方法。

      3、在一个Wrapper容器里,The basic valve负责加载与之关联的servlet的类以及相应The Request请求。

      4、在拥有孩子容器的Context,The basic Valve使用mapper组件目的就是找出负责处理The request请求的孩子容  器。如果能够找到孩子容器,那么the Context 容器就会调用孩子容器的the invoke方法。然后有返回到第一步。

   注解:这四个过程十分的重要,一定充分的了解。不理解的时候要反复的看,或者就是跟踪源码,这种设计思想非常值得学习。

    现在让我们看看实现处理的顺序。

  The SimpleContext类中的Invoke方法调用了the pipeline的invoke方法

 

     public void invoke(Request request,Response response)

         throws IOException,ServletException{

         pipeline.invoke(request,response);

    }

   The pipeline是有the SimplePipeline类代表,他的invoke方法调用方式如下面的代码:

 

/***
	 * 该方法交给内部类中的invokeNext(Request,Response)处理
	 */
	public void invoke(Request request, Response response) throws IOException,
			ServletException {
		(new SimplePipelineValveContext()).invokeNext(request, response);
	}

 这个在“Pipelining Task”部分已经解释了,这里就不解释。这个代码调用了所有添加在子容器的(Wrapper)的Valves的the invoke方法然后又调用了the basic valve的Invoke方法。在 SimpleContext容器中,The SimpleContextValve类代表the basic Valve。在调用这个基本阀门中的invoke方法时,the SimpleContextValve使用了the context 中的组件the mapper 查找一个wrapper:

       Wrapper wrapper=null;

       try{

                wrapper=(Wrapper)context.map(request,true);

 

         }

  如果the Wrapper找到了,就会调用The Wrapper的invoke方法:

      wrapper.invoke(request,response);

 

   在本应用程序中一个Wrapper是由the SimpleWrapper类代表的。下面SimpleWrapper中的the invoke方法代码与the SimpleContext类的invoke方法的代码是一样的.

 

 

     public void invoke(Request request,Response response)

         throws IOException,ServletException{

         pipeline.invoke(request,response);

    }

 

The pipeline是The SimplePipeline的实例(他的invoke方法已经在上面讨论了)。特别注意的是,本应用程序的The Wrappers没有the valves除了有the basic valve(它由The SimpleWrapperValve类代表)。The wrapper的pipeline调用了the SimpleWrapperValve类的invoke方法(主要是分配一个servlet以及调用该servlet的service方法)详细解释已经在“The Wrapper应用程序”解说了。

 

     还需要注意的是the wrapper容器是没有和a loader关联,而是与the context 容器关联的。因此the SimpleWrapper的getLoader方法返回父类中的loader.

 

     这里有四个类(SimpleContext,SimpleContextValve,SimpleContextMapper,Bootstrap2)在第一个应用程序没有解释,下面将会详细讨论这四个类。

 

 二、ex05.pyrmont.core.SimpleContextValve

       这个类代表了the SimpleContext容器的the basic valve,他的the invoke方法是十分关键的,可以看下面代码:

 

  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);
  }

 三、ex05.pyrmont.core.SimpleContextMapper

   The SimpleContextMapper类(它实现了org.apache.catalina.Mapper接口注意这是在Tomcat4)主要设计的思想就是与SimpleContext实例相关联。

package ex05.pyrmont.core;

import javax.servlet.http.HttpServletRequest;
import org.apache.catalina.Container;
import org.apache.catalina.HttpRequest;
import org.apache.catalina.Mapper;
import org.apache.catalina.Request;
import org.apache.catalina.Wrapper;

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);
  }
}

 如果你传过来的The Container不是the SimpleContext实例,那么The setContainer方法就会抛出一个 IllegalAgumentException异常。the map 方法返回了一个孩子容器(A wrapper只要负责处理the Request请求)。The Map 方法需要传两个参数(a request对象和一个布尔值)。这个实现忽略了第二个参数。该方法主要任务就是检索来自the request 对象的the context路径,然后使用了the Context的findServletMapping方法获得与路径相关联的名字。如果名字找到了,那么就是用the Context中的findChild方法获得一个Wrapper实例。

 

 

 四、ex05.prymont.core.SimpleContext

    在本应用程序中The SimpleContext类实现了The context接口。它是主要的容器,并且把自己赋给了the Connector.然而,在处理每个servlet是由a wrapper容器负责。本应用程序有两个servlet(PrimitiveServlet,ModernServlet),因此就需要两个Wrapper,他们的名字分别为Primitive、Modern。对于The SimpleContext决定每一次The request请求需要哪个wrapper的条件是:一定要the request URL 模式要与the wrapper的名字相匹配。在本应用程序中,我们有两个URL模式分别是用来调用两个wrapper的先决条件。第一个模式是/Primitive,它与the wrapper Primitive相匹配。第二个模式是/Modern,它与The Wrapper Modern相匹配。当然,你能够使用更多的模式给一个确定的servlet。你仅仅需要添加这些模式。

           The SimpleContext类实现了The Container和Context接口,所有存在许多方法。但是大部分方法是空实现的方法,然而与mapping相关的方法才是真正的代码(也就是本应用程序所需要的代码),这些方法可以看下面的描述.

 

       1、addServletMapping    添加一个URL pattern/wrapper匹配对。你添加的每个模式对是要调用哪个wrapper的一个先决条件。即The Context容器会根据模式匹配对来决断用哪个Wrapper容器(他的孩子容器)

 

        2、findServletMapping  通过一个URL模式获得the Wrapper的名字。这个方法就是根据URL模式找出要调用哪个Wrapper。如果用户用的URL模式没有在addServleyMapping方法添加,那么使用此方法返回null.

 

        3、 addMapper    添加一个组件mapper到the Context容器中。The SimpleContext类拥有the mapper和mappers两个成员变量。mapper是一个默认的mapper组件,mappers包含了The SimpleContext实例所有的mapper

。The first mapper添加到了这个SimpleContext中变成了一个默认的mapper组件。

 

         4、findMapper     找出一个正确的mapper组件。在 SimpleContext类中该方法是返回一个默认的组件mapper.

 

          5、map 返回一个负责处理的request请求的wrapper容器

 

     除此之外,SimpleContext类也实现了addChild,findChild,findChildren方法。The addChild方法就是把一个wrapper添加到the context中,the findChild方法通过一个具体的名字找出一个wrapper,findChildren方法是返回在SimpleContext实例中的所有的wrapper容器即它的所有孩子容器。

 

 四、ex05.pyrmont.startup.Bootstrap2

    The Bootstrap2类是一个启动本应用程序,这个类与BootStrap1功能代码十分相似,下面是其代码:

 

package ex05.pyrmont.startup;

import ex05.pyrmont.core.SimpleContext;
import ex05.pyrmont.core.SimpleContextMapper;
import ex05.pyrmont.core.SimpleLoader;
import ex05.pyrmont.core.SimpleWrapper;
import ex05.pyrmont.valves.ClientIPLoggerValve;
import ex05.pyrmont.valves.HeaderLoggerValve;
import org.apache.catalina.Context;
import org.apache.catalina.Loader;
import org.apache.catalina.Mapper;
import org.apache.catalina.Pipeline;
import org.apache.catalina.Valve;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.http.HttpConnector;

public final class Bootstrap2 {
  public static void main(String[] args) {
    HttpConnector connector = new HttpConnector();
    Wrapper wrapper1 = new SimpleWrapper();
    wrapper1.setName("Primitive");
    wrapper1.setServletClass("PrimitiveServlet");
    Wrapper wrapper2 = new SimpleWrapper();
    wrapper2.setName("Modern");
    wrapper2.setServletClass("ModernServlet");

    Context context = new SimpleContext();
    context.addChild(wrapper1);
    context.addChild(wrapper2);

    Valve valve1 = new HeaderLoggerValve();
    Valve valve2 = new ClientIPLoggerValve();

    ((Pipeline) context).addValve(valve1);
    ((Pipeline) context).addValve(valve2);

    Mapper mapper = new SimpleContextMapper();
    mapper.setProtocol("http");
    context.addMapper(mapper);
    Loader loader = new SimpleLoader();
    context.setLoader(loader);
    // context.addServletMapping(pattern, name);
    context.addServletMapping("/Primitive", "Primitive");
    context.addServletMapping("/Modern", "Modern");
    connector.setContainer(context);
    try {
      connector.initialize();
      connector.start();

      // make the application wait until we press a key.
      System.in.read();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 主方法开始实例化Tomcat 默认的连接器,两个wrappers,wrapper1,wrapper2.这些Wrappers的确定的名字是Primitive和Modern,而Primitiv,Modern对应的Servlet类分别是PrimitiveServlet,ModernServlet

 

 

 HttpConnector connector = new HttpConnector();
    Wrapper wrapper1 = new SimpleWrapper();
    wrapper1.setName("Primitive");
    wrapper1.setServletClass("PrimitiveServlet");
    Wrapper wrapper2 = new SimpleWrapper();
    wrapper2.setName("Modern");
    wrapper2.setServletClass("ModernServlet");

 然后,主方法创建了一个SimpleContext实例,SimpleContext容器又添加了wrapper1,wrapper2作为孩子容器。也实例化两个valve:ClientIPLogger,HeaderLoggerValve并且把两个Valve添加到SimpleContext容器中。

 

    Context context = new SimpleContext();
    context.addChild(wrapper1);
    context.addChild(wrapper2);

    Valve valve1 = new HeaderLoggerValve();
    Valve valve2 = new ClientIPLoggerValve();

    ((Pipeline) context).addValve(valve1);
    ((Pipeline) context).addValve(valve2);

 接下来,主方法就构造一个mapper对象(The SimpleMapper类),并把该组件添加到SimpleContext容器中。这个mapper组件主要负责找出在Context容器中的孩子容器(专门处理Http请求)

 

 

    Mapper mapper = new SimpleContextMapper();
    mapper.setProtocol("http");
    context.addMapper(mapper);

 对于加载一个servlet你就需要一个Loader.在这里你使用了SimpleLoader类,正如第一个应用程序那样。然而,The Loader 添加到The Context 容器中,这样就可以为两个wrappers共同使用这个加载器了。The Wrappers将使用getLoader找出the loader,因为the Context是the Wrapper的父容器。

Loader loader = new SimpleLoader();
    context.setLoader(loader);
 

现在,该是时候添加servlet的匹配模式了。你要添加两个模式给这两个wrappers

 

 

    context.addServletMapping("/Primitive", "Primitive");
    context.addServletMapping("/Modern", "Modern");

 最后,要把the Context容器传给the connector,然后启动the connector

 

 connector.setContainer(context);
    try {
      connector.initialize();
      connector.start();

      // make the application wait until we press a key.
      System.in.read();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

 五、运行这个应用程序

     这里翻译我就不详细说了

 

 六、总结

     介绍完the connector后,The Container是第二个主要的模块。The Container使用许多的其他模块,如:Loader,Logger,Manager等等。这里也有四种类型的容器:Engine,Host,Context,Wrapper.一个Catalina部署是不会把四个容器全部的展现出来。在这章中的两个应用表明了一个部署可以有单个的wrapper容器或者是由多个Wrapper容器组成的Context容器。

  • 大小: 157.5 KB
1
0
分享到:
评论
3 楼 he_wen 2011-10-29  
看不懂自己下载源代码 单步调试跟踪代码 可以介入eclipse插件relo 转换成类结构分析源代码
2 楼 乌索普 2011-10-25  
非常鼓励,不过当看到孩子容器的时候,我有点吃不消,
1 楼 aixuebo 2010-12-07  
给点鼓励,翻译的不错。。。我曾经也翻译过,但是没有分享出来,原因就是自己太懒了,挺佩服你的精神的。以后向你学习。

相关推荐

    how tomcat works——(5)容器

    3. 容器级配置:容器可以根据需要提供全局的配置,比如全局的Filter或Listener,这些配置对整个Web应用或特定的Host、Context有效。 五、容器与源码分析 了解了容器的基本概念后,对于开发者来说,阅读Tomcat的源码...

    How Tomcat Works【英文PDF+中文HTML+源码】.zip

    《How Tomcat Works》是一份深入探讨Apache Tomcat工作原理的重要资源,包含了英文PDF文档、中文HTML翻译以及源代码,旨在帮助读者理解Tomcat服务器的内部运作机制。这份资料是IT从业者,特别是Java Web开发者、系统...

    How Tomcat Works 中文版+例程源码

    《How Tomcat Works》是一本深入探讨Apache Tomcat工作原理的书籍,中文版的提供使得国内开发者能够更方便地理解这一流行的开源Java Servlet容器。这本书不仅涵盖了Tomcat的基础知识,还详细解析了其内部机制,对于...

    How Tomcat works(PDF)

    《How Tomcat Works》这本书深入浅出地介绍了Apache Tomcat这款广泛应用的Java Servlet容器的工作原理。Tomcat作为开源软件,是许多Web应用的基础,尤其在轻量级开发和测试环境中非常常见。以下是对Tomcat核心知识点...

    How Tomcat Works 中文版

    《How Tomcat Works》是一本深入探讨Apache Tomcat工作原理的中文版书籍,对于Java Web开发者来说,理解Tomcat的工作机制至关重要。Tomcat是Apache软件基金会的Jakarta项目中的一个核心部分,它是一个开源的、免费的...

    HowTomcatWorks 中文版+源码.rar

    《HowTomcatWorks》是一本深入解析Apache Tomcat工作原理的书籍,中文版的发布使得更多的中国开发者能够理解和掌握这款广泛应用的开源Java Servlet容器的工作机制。Tomcat是Apache软件基金会Jakarta项目的一部分,它...

    how tomcat works中英文版

    《How Tomcat Works》是一本深入探讨Apache Tomcat工作原理的书籍,包含了中英文两个版本。这本书对于理解Java Servlet和JavaServer Pages(JSP)容器的运作方式具有极高的价值,特别是对于那些想要深入理解Web应用...

    how tomcat works

    《how tomcat works》是一本深入探讨Apache Tomcat内部工作原理的专业书籍。Apache Tomcat是一个开源的Java Servlet容器,它实现了Java Servlet和JavaServer Pages技术规范,提供了Java Web服务器的功能。对于Java ...

    HowTomcatWorks(书和源码)

    《How Tomcat Works》是一本深入解析Apache Tomcat工作原理的书籍,同时也包含了源码,为读者提供了理论与实践相结合的深入学习体验。Tomcat是一款广泛使用的开源Java Servlet容器,它是Apache软件基金会 Jakarta...

    How Tomcat Works 中文版/英文版 + 源码

    《How Tomcat Works》是一本深入解析Apache Tomcat服务器内部工作原理的重要参考资料,它提供了对Tomcat架构的全面理解,包括其设计、配置和优化。这本书的中文版和英文版都为读者提供了便利,无论你是母语为中文...

    how tomcat works 中文版及源码

    《How Tomcat Works》是一本深入解析Apache Tomcat工作原理的书籍,中文版的出现使得国内开发者能够更方便地理解这个流行的Java Servlet容器。Tomcat是开源软件,它实现了Java Servlet和JavaServer Pages(JSP)规范...

    &lt;&lt;How tomcat works&gt;&gt; 英文版 中文版 源码

    《How Tomcat Works》是一本深入解析Apache Tomcat工作原理的经典书籍,对于Java Web开发者来说,它是理解Tomcat内部机制的重要资源。这本书分为英文版和中文版,方便不同语言背景的读者阅读。同时,源码的提供使得...

    How Tomcat Works以及案例的项目源码

    《How Tomcat Works》是一本深入探讨Apache Tomcat工作原理的专业书籍,对于任何希望深入了解Java Servlet和JavaServer Pages (JSP)容器的人来说,都是一份宝贵的资源。Tomcat作为最流行的开源Servlet容器,其内部...

    How tomcat works(包含源码示例)

    《How Tomcat Works》这本书深入剖析了Tomcat服务器的工作原理,是Java开发者深入理解Servlet容器不可或缺的参考资料。Tomcat作为Apache软件基金会的项目,是开源的、轻量级的Servlet和JSP容器,广泛应用于各种Web...

    WEB服务器工作机制由浅至深(2):【How Tomcat Works】1~4章翻译分析

    本篇文章将深入探讨Tomcat,一个广泛使用的Java Web服务器,通过翻译分析"How Tomcat Works"一书的前四章内容,来理解其工作机制。 首先,我们要了解Tomcat的基本架构。Tomcat是Apache软件基金会的Jakarta项目中的...

    HowTomcatWorks-master.zip

    "HowTomcatWorks"项目,正如其名,旨在帮助开发者了解Tomcat的工作原理,通过源代码分享,使我们有机会深入探究这个强大的服务器内部机制。 1. **Tomcat架构概览** Tomcat的架构设计分为几个主要部分:Catalina...

Global site tag (gtag.js) - Google Analytics