【0】README
0.0)本文部分文字描述转自:“深入剖析tomcat”,旨在学习 tomcat(5)servlet容器 的基础知识;
0.1)intro to servlet容器:servlet容器是用来处理请求servlet资源,并为web客户端填充response 对象的模块;
0.2)补充:吃个饭过来,真心没想到这么多人围观,再次对文章重新排版(并不是博主我不给力,是CSDN编辑器时不时吊链子啊,oh),并添加了测试用例的程序流程图(共3张)[1604111947];
0.3)通知:本文由于CSDN编辑器掉链子使得博文排版乱八七糟,故晚辈我又重新进行了排版,请大家移步到 tomcat(5)servlet容器(lastest version),本文明天也会删除[1604112328]。
【1】Container接口
1)在Tomcat中,共有四种容器(types):(干货——Tomcat中共有4种容器)
t1)Engine:表示整个Catalina servlet 引擎;
t2)Host:表示包含有一个或多个 Context容器的虚拟主机;
t3)Context:表示一个web 应用程序,一个Context 可以有多个 Wrapper;
t4)Wrapper:表示一个独立的servlet;
2)以上4中容器都是 org.apache.catalina包下的接口:分别为Engine,Host, Context, Wrapper,他们都继承自Container接口。这4个接口的标准实现是 StandardEngine类,StandardHost类,StandardContext类,StandardWrapper类,他们都在 org.apache.catalina.core 包内;
Attention)
A1)所有的实现类都继承自抽象类 ContainerBase ;
A2)Container接口的设计满足以下条件:在部署应用时,Tomcat管理员可以通过编辑配置文件(server.xml)来决定使用哪种容器。这是通过引入容器中的管道(pipeline)和阀(valve)的集合实现的;(干货——引入了容器中的管道和阀)
【2】管道任务
1)本节旨在说明:当连接器调用了servlet容器的invoke方法后会发生什么事情,并讨论org.apache.catalina 包中的4个相关接口,Pipeline, Valve, ValveContext 和 Contained;
2)管道和阀:
2.1)管道:包含该servlet容器将要调用的任务;
2.2)一个阀:表示一个具体的任务。
2.3)在servlet容器的管道中,有一个基础阀,但是,可以添加任意数量的阀。阀的数量指的是额外添加的阀数量,即,不包括基础阀。有意思的是, 可以通过编辑tomcat 的 配置文件(server.xml)来动态地添加阀;
2.4)一条管道和阀的示意图如下:

Attention)
A1)管道就想过滤器链条一样,而阀则好似过滤器;
A2)当一个阀执行完成后,会调用下一个阀继续执行。基础阀总是最后一个执行;(干货——当一个阀执行完成后,会调用下一个阀继续执行。基础阀总是最后一个执行)
3)管道的invoke方法:一个servlet容器可以有一条管道,当调用了容器的invoke方法后,容器会将处理工作交由管道完成,而管道会调用其中的第一个阀开始处理。当第一个阀处理完后,它会调用后续的阀继续执行任务,直到管道中所有的阀都处理完成。下面是invoke方法的伪代码:
import java.io.IOException;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.Locale;
import java.util.ResourceBundle;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.Locale;
import java.util.ResourceBundle;

// invoke each valve added to the pipeline,先是非基础阀调用 invoke方法
for(;;){valve[i].invoke();
}
// then, invoke the basic valve, 后是基础阀调用 invoke方法(基础阀最后一个调用invoke方法)
basicValve.invoke(...);public void invoke(Request request, Response response) // SimplePipeline.invoke()throws IOException, ServletException {// Invoke the first Valve in this pipeline for this request(new SimplePipelineValveContext()).invokeNext(request, response);}
public void invokeNext(Request request, Response response) // SimplePipeline.invokeNext()throws IOException, ServletException {int subscript = stage;stage = stage + 1;// Invoke the requested Valve for the current request threadif (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

4)实现阀的遍历:Tomcat引入接口 org.apache.catalina.ValveContext 来实现阀的遍历执行;
4.1)管道必须保证添加到其中的所有阀和基础阀都被调用一次:这是通过调用一个 ValveContext接口实例来实现的。
4.2)ValveContext接口中最重要的方法是 invokeNext方法:在创建了ValveContext实例后,管道会调用ValveContext实例的 invokeNext方法。ValveContext实例会首先调用管道中的 第一个阀,第一个阀执行完后,会调用后面的阀继续执行。ValveContext实例会将自身传给每个阀,因此,每个阀都可以调用 ValveContext实例的 invokeNext方法;
5)org.apache.catalina.core.StandardPipeline类:是所有servlet容器中的Pipeline接口的实现,Tomcat4中有一个实现了ValveContext接口的内部类,名为StandardPipelineValveContext;
6)Tomcat5 从 StandardPipeline类中移除了 StandardPipelineValveContext类:却使用 org.apache.catalina.core.StandardValveContext类来调用阀;
【2.1】Pipeline接口
1)对于Pipeline接口:首先要提到的一个方法是 invoke方法,servlet容器调用invoke方法来开始调用管道中的阀和基础阀;
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);
} 

2)getBasic和setBasic:setBasic方法将基础阀设置到管道中,getBasic获取基础阀;(干货——管道中可以指定基础阀)
3)addValve和removeValve:新增阀和删除阀;(干货——在管道中可以新增和删除非基础阀)
【2.2】Valve接口
1)阀是Valve接口的实例,用来处理接收到的请求,有两个方法:invoke方法和getinfo方法;

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

【2.3.】ValveContext接口
1)有两个方法:invokeNext方法和 getInfo方法;
【2.4】Contained接口
public interface Contained {   public Container getContainer();public void setContainer(Container container);
} 

【3】Wrapper接口
1)intro to Wrapper: Wrapper级的servlet容器是一个 org.apache.catalina.Wrapper接口的实例,表示一个独立的servlet定义。Wrapper接口继承自 Container接口,又添加了一些额外的方法。
public interface Wrapper extends Container {     public long getAvailable();public void setAvailable(long available);public String getJspFile(); public void setJspFile(String jspFile); public int getLoadOnStartup(); public void setLoadOnStartup(int value); public String getRunAs(); public void setRunAs(String runAs); public String getServletClass(); public void setServletClass(String servletClass); public boolean isUnavailable(); public void addInitParameter(String name, String value);     public void addInstanceListener(InstanceListener listener);     public void addSecurityReference(String name, String link);     public Servlet allocate() throws ServletException;     public void deallocate(Servlet servlet) throws ServletException;     public String findInitParameter(String name);    public String[] findInitParameters();     public String findSecurityReference(String name);     public String[] findSecurityReferences();    public void load() throws ServletException;    public void removeInitParameter(String name); public void removeInstanceListener(InstanceListener listener);     public void removeSecurityReference(String name);  public void unavailable(UnavailableException unavailable);   public void unload() throws ServletException;
}

2)Wrapper接口的实现类:要负责管理继承servlet类的servlet生命周期,即,调用 servlet的 init(), service(), destroy()方法;
3)由于Wrapper已经是最低级的容器了,不能再向其中添加子容器;(干货——Wrapper已经是最低级的servlet容器)
4)Wrapper接口有两个方法:load方法 和 allocate方法;
4.1)load方法:载入并初始化servlet类;
4.2)allocate方法:会分配一个已经初始化的servlet实例;
【4】Context接口
1)intro to Context:Context接口是一个web 应用程序,一个Context实例可以有一个或多个Wrapper实例作为其子容器;
2)比较重要的方法: addWrapper() and createWrapper();
【5】Wrapper 应用程序(demonstrate how to build a smallest servlet container)
1)SimpleWrapper类:该类实现了Wrapper接口,包含一个Pipeline实例,并使用Loader实例载入servlet类。Pipeline实例包含一个基础阀和两个额外的阀。
【5.1】SimpleLoader类
1)SimpleLoader:负责完成类的载入工作,它知道servlet类的位置,通过调用其getClassLoader可以返回一个 java.lang.ClassLoader实例,可以用来搜索servlet类的位置;
2)SimpleLoader的构造函数:会初始化类加载器,供 SimpleWrapper实例使用;
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() );}}

【5.2】SimplePipeline类
1)该类最重要的方法是 invoke方法;
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 Valvesprotected 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 threadif (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
}

【5.3】SimpleWrapper类
1)该类实现了Wrapper接口:并提供了 allocate 和 load 方法的实现;
2)getLoader()方法:该方法返回一个用于载入servlet 类的载入器。若Wrapper实例已经关联了一个载入器,则直接将其返回;否则,它将返回父容器的载入器。若没有父容器,getLoader方法会返回null;
3)SimpleWrapper类:有一个Pipeline实例,并该为Pipeline实例设置基础阀;
public class SimpleWrapper implements Wrapper, Pipeline {// the servlet instanceprivate Servlet instance = null;private String servletClass;private Loader loader;private String name;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 necessaryif (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 usedif (loader==null) {throw new ServletException("No loader.");}ClassLoader classLoader = loader.getClassLoader();// Load the specified servlet class from the appropriate class loaderClass 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 itselftry {servlet = (Servlet) classClass.newInstance();}catch (Throwable e) {throw new ServletException("Failed to instantiate servlet");}// Call the initialization method of this servlettry {servlet.init(null);}catch (Throwable f) {throw new ServletException("Failed initialize servlet.");}return servlet;}public String getInfo() {return null;}public Loader getLoader() {if (loader != null)return (loader);if (parent != null)return (parent.getLoader());return (null);}

【5.4】SimpleWrapperValve类
1)SimpleWrapperValve是一个基础阀:用于处理读iSimpleWrapper类的请求,其最主要的方法是 invoke方法;
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 requesttry {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;}
}

【5.5】ClientIPLoggerValve类
1)ClientIPLoggerValve类所表示的阀:用来将client的IP 地址输出到控制台上;
2)注意其invoke方法:它先调用方法参数 valveContext的 invokeNext方法来调用管道中的下一个阀。然后,它会把几行字符串output到 console;
public class ClientIPLoggerValve implements Valve, Contained {protected Container container;public void invoke(Request request, Response response, ValveContext valveContext)throws IOException, ServletException {// Pass this request on to the next valve in our pipelinevalveContext.invokeNext(request, response);System.out.println("Client IP Logger Valve");ServletRequest sreq = request.getRequest();System.out.println(sreq.getRemoteAddr());System.out.println("------------------------------------");}public String getInfo() {return null;}public Container getContainer() {return container;}public void setContainer(Container container) {this.container = container;}
}

【5.6】HeaderLoggerValve类
1)HeaderLoggerValve类作用:会把请求头信息output到 console;
2)注意其invoke方法:它先调用方法参数 valveContext的 invokeNext方法来调用管道中的下一个阀。
public class HeaderLoggerValve implements Valve, Contained {protected Container container;public void invoke(Request request, Response response, ValveContext valveContext)throws IOException, ServletException {// Pass this request on to the next valve in our pipelinevalveContext.invokeNext(request, response);System.out.println("Header Logger Valve");ServletRequest sreq = request.getRequest();if (sreq instanceof HttpServletRequest) {HttpServletRequest hreq = (HttpServletRequest) sreq;Enumeration headerNames = hreq.getHeaderNames();while (headerNames.hasMoreElements()) {String headerName = headerNames.nextElement().toString();String headerValue = hreq.getHeader(headerName);System.out.println(headerName + ":" + headerValue);}}elseSystem.out.println("Not an HTTP Request");System.out.println("------------------------------------");}public String getInfo() {return null;}public Container getContainer() {return container;}public void setContainer(Container container) {this.container = container;}
}

【5.7】Bootstrap1
step1)创建 HttpConnector 和 SimpleWrapper实例,并将需要加载的 servlet name 赋值给 Wrapper实例;
step2)创建一个载入器和两个阀,将载入器设置到Wrapper实例中 ;
step3)将上述创建的两个阀添加到 Wrapper的管道中;
step4)将Wrapper 实例设置为 连接器的servlet容器,并初始化并启动连接器; 
public final class Bootstrap1 {public static void main(String[] args) {/* call by using http://localhost:8080/ModernServlet,but could be invoked by any name */HttpConnector connector = new HttpConnector();Wrapper wrapper = new SimpleWrapper();wrapper.setServletClass("servlet.ModernServlet"); // 设置servlet的相对路径
    Loader loader = new SimpleLoader(); // 类加载器Valve valve1 = new HeaderLoggerValve(); // 把请求头信息output到 consoleValve valve2 = new ClientIPLoggerValve();// 用来将client的IP 地址输出到控制台上
wrapper.setLoader(loader);((Pipeline) wrapper).addValve(valve1);((Pipeline) wrapper).addValve(valve2);connector.setContainer(wrapper);try {connector.initialize(); // 创建服务器套接字connector.start(); // // make the application wait until we press a key.
      System.in.read();}catch (Exception e) {e.printStackTrace();}}
}

Attention)我这里总结了该测试用例的调用流程图
【5.8】运行应用程序
1)运行参数
E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src>java -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\webroot com.tomcat.chapter5.startup/Bootstrap1
HttpConnector Opening server socket on all host IP addresses
HttpConnector[8080] Starting background thread
ModernServlet -- init
Client IP Logger Valve
127.0.0.1
------------------------------------
Header Logger Valve
host:localhost:8080
connection:keep-alive
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
user-agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36
accept-encoding:gzip, deflate, sdch
accept-language:zh-CN,zh;q=0.8,en;q=0.6
------------------------------------
Client IP Logger Valve
127.0.0.1
------------------------------------
Header Logger Valve
host:localhost:8080
connection:keep-alive
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
user-agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36
accept-encoding:gzip, deflate, sdch
accept-language:zh-CN,zh;q=0.8,en;q=0.6
------------------------------------

2)运行结果
【6】Context应用程序
0)intro to Context app:本app 展示了如何使用一个包含了两个Wrapper实例的Context实例来构建web app, 这两个Wrapper 实例包装了两个servlet类,当应用程序有多个 Wrapper实例时,需要使用一个 映射器。映射器是组件,帮助servlet容器(Context实例)选择一个子容器来处理某个指定的请求;
1)虽然有些应用程序只需要一个servlet,但大部分web app 是需要多个servlet合作的。这些应用程序中,需要的servlet容器是Context,不是Wrapper;
2)本应用程序的映射器:是SimpleContextMapper类的实例,该类实现类Mapper接口,servlet容器可以使用多个 映射器来支持不同的协议。
public interface Mapper {public Container getContainer(); // 返回与该映射器相关联的servlet容器的实例;public void setContainer(Container container); // 设置与该映射器相关联的servlet容器;public String getProtocol(); // 返回该映射器负责处理的协议public void setProtocol(String protocol);    //指定该映射器负责处理哪种协议public Container map(Request request, boolean update); // 返回要处理某个特定请求的子容器的实例;
}

3)SimpleContext类:是Context容器的一个实例,它使用了SimpleContextMapper 类的实例作为其映射器,将SimpleContextValve 的实例作为基础阀;
4)Context容器中额外添加了两个阀: ClinetIPLoggerValve 和 HeaderLoggerValve,并包含两个 Wrapper 实例作为其子容器,二者都是 SimpleWrapper 实例;这两个Wrapper实例使用 SimpleWrapperValve 实例作为其基础阀,不再添加其他阀;
5)剩下的内容包括:

step1)容器包含一个管道,容器的invoke方法会调用管道的invoke方法;
step2)管道的invoke方法会调用所有添加到其容器中的阀,然后再调用其基础阀的invoke方法;
step3)在Wrapper实例中, 基础阀负责载入相关联的servlet类,并对请求进行响应;
step4)在包含子容器的 Context实例中, 基础阀使用映射器来查找一个子容器,该子容器负责处理接收到的请求。若找到了相应的子容器,则调用其invoke方法,转到step1继续执行;
6)下面对上述的steps 做 detailed intro
step1)SimpleContext类的invoke方法调用管道的invoke方法:
step2)管道SimplePipeline的invoke如下:
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); // 会调用所有添加到Context 实例中的阀,然后再调用基础阀的invoke方法;}
step3)SimpleContext类中,基础阀是 SimpleContextValve类的实例。在SimpleContextValve类的 invoke方法中, SimpleContextValve实例使用了 Context实例的映射器来查找 Wrapper容器;
public class SimpleContext implements Context, Pipeline {public SimpleContext() {pipeline.setBasic(new SimpleContextValve());}
public void invoke(Request request, Response response, ValveContext valveContext)  // SimpleContextValve.invoke()throws IOException, ServletException {// Validate the request and response object typesif (!(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-INFHttpServletRequest 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 RequestWrapper wrapper = null;try {wrapper = (Wrapper) context.map(request, true); // attention for this line.}catch (IllegalArgumentException e) {badRequest(requestURI, (HttpServletResponse) response.getResponse());return;}if (wrapper == null) {notFound(requestURI, (HttpServletResponse) response.getResponse());return;}// Ask this Wrapper to process this Requestresponse.setContext(context);wrapper.invoke(request, response);}

Attention)
A1)Wrapper实例的管道会调用 SimpleWrapperValve类的 invoke方法,它会分配servlet实例,并调用其 service方法;
A2)Wrapper实例中:并没有与载入器相关联,但是Context 实例关联了类载入器,因此,SimpleWrapper类的 getLoader() 方法会返回父容器的载入器;
 
【6.1】SimpleContextValve类
1)该类是 SimleContext的基础阀,最重要的方法是invoke方法;
【6.2】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 mappedString 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 specificationWrapper wrapper = null;String servletPath = relativeURI;String pathInfo = null;String name = context.findServletMapping(relativeURI);if (name != null)wrapper = (Wrapper) context.findChild(name);return (wrapper);}
}

1)map方法需要两个参数:一个request对象和一个布尔变量。
2)在本app中, 忽略了第2个参数。map() 方法:会从request对象中解析出请求的上下文路径,并调用 Conetext 实例的findServletMapping() 方法 来获取一个与该路径相关联的名称,如果找到了这个名称,则它调用 Context实例的findChild方法获取一个 Wrapper 实例;
【6.3】SimpleContext类
1)intro to SimpleContext: 该类是 Context容器 的实例,是与连接器相关联的主容器;
2)本应用程序有两种URL模式:用来调用两个 Wrapper实例,如/Primitive 和 /Modern 模式;当然,也可以将多个 URL模式映射到一个Wrapper实例上。只需要添加这些模式即可;
3)SimpleContext类必须实现 Container 和 Context接口,实现的方法包括以下几个(methods):
method1)addServletMapping(): 添加一个 URL模式 / Wrapper实例的名称对;通过给定的名称添加用于调用Wrapper实例的每种模式;
method2)findServletMapping():通过URL模式 查找对应的Wrapper 实例名称;该方法用来查找某个特殊URL 模式对应的Wrapper实例;
method3)addMapper():在Context容器中添加一个映射器。SimpleContext类声明有两个变量: mapper and mappers 。mapper表示程序使用的默认映射器,mappers包含SimpleContext 实例中所有可用的映射器。第一个被添加到 Context容器中的映射器称为默认映射器;
method4)findMapper():找到正确的映射器,在 SimpleContext类中,它返回默认映射器;
method5)map(): 返回负责处理当前请求的 Wrapper实例;
【6.4】BootStrap2
step1)首先实例化Tomcat的默认连接器,创建两个Wrapper实例,并指定名称。
 HttpConnector connector = new HttpConnector();Wrapper wrapper1 = new SimpleWrapper();wrapper1.setName("Primitive");wrapper1.setServletClass("servlet.PrimitiveServlet");Wrapper wrapper2 = new SimpleWrapper();wrapper2.setName("Modern");wrapper2.setServletClass("servlet.ModernServlet");

step2)main() 方法创建一个 SimpleContext实例,并将 wrapper1 和 wrapper2 作为子容器添加到 SimpleContext 实例中。此外,它还会实例化两个阀:ClientIPLoggerValve 和 HeaderLoggerValve,并将它们添加到 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);

step3)接下来,它会从SimpleMapper类创建一个映射器对象,将其添加到 SimpleContext 实例中。映射器负责查找Context 实例中的子容器来处理 HTTP请求
Mapper mapper = new SimpleContextMapper();mapper.setProtocol("http");context.addMapper(mapper);

step4)要载入servlet类,还需要一个载入器。并将其添加到 Context实例中。Wrapper实例可以通过 其 getLoader方法来获取载入器,因为Wrapper实例是 Context实例的子容器:
Loader loader = new SimpleLoader();context.setLoader(loader);

step5)添加servlet映射。为 两个Wrapper 实例添加两种模式:
 // context.addServletMapping(pattern, name);context.addServletMapping("/Primitive", "Primitive");context.addServletMapping("/Modern", "Modern");

step6)将Context容器与 连接器相关联,并初始化连接器,调用其 start方法;
connector.setContainer(context);try {connector.initialize();connector.start();// make the application wait until we press a key.System.in.read();}

【6.5】运行应用程序
1)运行参数
E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src>java -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\webroot  com.tomcat.chapter5.startup.
Bootstrap2
HttpConnector Opening server socket on all host IP addresses
HttpConnector[8080] Starting background thread
Client IP Logger Valve
127.0.0.1
------------------------------------
Header Logger Valve
host:localhost:8080
connection:keep-alive
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
user-agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36
accept-encoding:gzip, deflate, sdch
accept-language:zh-CN,zh;q=0.8,en;q=0.6
------------------------------------
init
from service
Client IP Logger Valve
127.0.0.1
------------------------------------

2)运行结果
 

tomcat(5)servlet容器相关推荐

  1. tomcat(5)servlet容器(lastest version)

    [0]README 0.0)本文部分文字描述转自:"深入剖析tomcat",旨在学习 tomcat(5)servlet容器 的基础知识: 0.1)intro to servlet容 ...

  2. SpringBoot之配置嵌入式Servlet容器

    1.概述 文章目录 1.概述 2.如何修改SpringBoot的默认配置 3.定制和修改Servlet容器的相关配置 4.注册Servlet三大组件 5.替换为其他嵌入式Servlet容器 6.嵌入式 ...

  3. Spring Boot切换其他嵌入式的Servlet容器

    Spring Boot默认支持: Tomcat(默认使用) <dependency><groupId>org.springframework.boot</groupId& ...

  4. Spring boot切换Servlet容器

    切换Servlet容器 Spring boot默认配置Tomcat作为Servlet容器 引入web模块,默认使用嵌入式的Tomcat 可以切换Jetty.Undertow 默认配置 Pom文件,查看 ...

  5. servlet容器_Tomcat 容器与servlet的交互原理

    点击蓝字"程序员考拉"欢迎关注! Tomcat 是Web应用服务器,是一个Servlet/JSP容器. Tomcat 作为Servlet容器,负责处理客户请求,把请求传送给Serv ...

  6. tomcat和servlet的关系

    tomcat和servlet的关系 Tomcat 是Web应用服务器,是一个Servlet/JSP容器. Tomcat 作为Servlet容器,负责处理客户请求,把请求传送给Servlet,并将Ser ...

  7. spring boot没有web.xml,如何向嵌入式的servlet容器中注册servlet组件

    1. Spring boot默认使用Tomcat作为嵌入式的servlet容器,只要引入spring-boot-starter-web依赖,就会默认用Tomcat作为servlet容器. 2. Spr ...

  8. tomcat和servlet的关系及区别

    tomcat和servlet的关系及区别 Tomcat 是Web应用服务器,是一个Servlet/JSP容器. Tomcat 作为Servlet容器,负责处理客户请求,把请求传送给Servlet,并将 ...

  9. springboot-嵌入式Servlet容器(Tomcat)源码分析以及容器切换

    目录 一.springboot的嵌入式Servlet容器(tomcat) 1.原理 2.源码 (1)ServletWebServerApplicationContext的createWebServer ...

最新文章

  1. 如何给6个整数的一维数组某个元素赋值_数组指针详解
  2. Model-View-Presenter模式之 Step by Step
  3. php面向对象公共类,PHP面向对象(一):类与类的实例化
  4. Oleans集群之Consul再解释
  5. xss原理和注入类型
  6. 关于7z结尾的压缩包操作系统
  7. 计算机春季高考试题答案,最新春季高考历年真题-天津市春季高考计算机试卷...
  8. 免费的matlab程序学习下载网站总结
  9. 深度解析copy与strong的区别
  10. Navicat远程连接服务器mysql,先后报错10060,10061
  11. java操作mysql临时表_MySQL 临时表
  12. 花生壳内网发布外网可以访问的网站
  13. kong插件之Rate Limiting
  14. ServiceComb 课程
  15. 【花雕体验】05 搭建行空板开发环境之SSH连接与Jupyter编程
  16. 『Python核心技术与实战』pandas.DataFrame()函数介绍
  17. 【高项】第3章 项目立项管理【知识点精华笔记】
  18. 台式计算机的辐射,台式电脑哪个部分辐射比较大?
  19. 语音视频社交中回声消除技术是如何实现的
  20. selenium 模拟 填问卷 问卷星

热门文章

  1. 【CF1209E】Rotate Columns【状压DP】【位运算】【贪心】
  2. 牛客题霸 [数组中未出现的最小正整数] C++题解/答案
  3. 铺地毯(矩形的交+前后缀矩形交)
  4. 一二三系列之状压DP——Max Correct Set(一)Neko Rules the Catniverse (Large Version)(二)Make It Ascending(三)
  5. YBTOJ:斐波拉契(矩阵快速幂)
  6. CSP2021NOIP2021游记
  7. P4103-[HEOI2014]大工程【虚树,dp】
  8. GDOI2020游记
  9. P2796-Facer的程序【dp】
  10. jzoj4800-[GDOI2017模拟9.24]周末晚会【dp,循环重构】