希望各位网友在看完<<how tomcat works>>一书或者鄙人的tomcat专栏文章后再看这篇博客

这里主要是梳理各个章节的核心概念

第一章 一个简单的Web服务器

第1章从这本书一开始就介绍了一个简单的HTTP服务器。要建立一个可工作的HTTP服务器,你需要知道在 java.net 包里边的 2 个类的内部运作:Socket 和 ServerSocket。这里有关于这 2个类足够的背景资料,使得你能够理解附带程序是如何工作的。

类图如下:


how tomcat works 总结_socket


程序的main方法中,建立HttpServer,调用await方法,从ServerSocket中取得inputstream与outputstream分别传递给Request类与Response类,最后调用Response的sendStaticResource方法.静态资源的处理方法就是,在默认的文件路径下按照分析出来的uri读取对应的文件,然后再调用outputstream的write方法。



第二章 一个简单的servlet容器

第一章的程序,只能处理静态资源,这一章的程序就能处理简单的servlet。

第 2 章说明简单的 servlet 容器是如何工作的。这一章带有 2 个 servlet 容器应用,可以处理静态资源和简单的 servlet 请求。尤其是你将会学到如何创建 request 和 response 对象,然后把它们传递给被请求的 servlet 的 service 方法。在 servlet 容器里边还有一个 servlet,你可以从一个 web 浏览器中调用它。

类图如下:


how tomcat works 总结_读书笔记_02


核心代码如下:

how tomcat works 总结_源码_03

HttpServer有两个处理器,分别为ServletProcessor与StaticResourceProcessor。到底使用哪个,取决于分析到的uri的开头。


在ServletProcessor中,会指定默认的文件路径,路径下有servlet的class文件,我们用URLClassLoader加载从uri中分析得到的servletname,得到servlet后,调用service方法即可。


在StaticResourceProcessor中,直接调用Response的sendStaticResource方法。


不过这里有些问题


Request方法会作为参数被传递到servelt中,而Request类里面有public型的parse方法与sendStaticResource方法,但是这两个方法不应该在servlet中被调用!总不能把两个方法改为private吧.一种方法是将两个方法的访问限制符置空,就是默认的限制符,它是不能在包外被访问的。


不过还有另一种方法,门面模式


如下图:

how tomcat works 总结_servlet_04

RequestFacade类接收一个Request对象传递给其成员变量ServletRequest,


public class RequestFacade implements ServletRequest {

private ServletRequest request = null;

public RequestFacade(Request request) {
this.request = request;
}

/* implementation of the ServletRequest*/
public Object getAttribute(String attribute) {
return request.getAttribute(attribute);
}
}

看到了吧,RequestFacade只是一个二传手,不过里面根本就没有parse方法。所以把RequestFacade作为参数传递给servlet是安全的。


所以,以后什么地方要用parse方法,就给它传Request对象;不能用parse的地方就传RequestFacade。



第三章 连接器

第3章介绍了一个简化版本的Tomcat 4默认连接器。这章里边的程序提供了一个学习工具,用于理解第 4 章里边的讨论的连接器。

本章类图


how tomcat works 总结_servlet_05


这里的HttpConnector做的工作就创建一个套接字,然后传递给HttpProcessor,在HttpProcessor的process方法中

parseRequest(input, output);

parseHeaders(input);

以上两个方法是最重要的;


这一章最复杂的地方其实在于解析HTTP请求


可以分为5步:


读取套接字的输入流;


解析请求行


解析请求头


解析cookie


获取参数


后面的代码如下:


parseRequest(input, output);
parseHeaders(input);

//check if this is a request for a servlet or a static resource
//a request for a servlet begins with "/servlet/"
if (request.getRequestURI().startsWith("/servlet/")) {
ServletProcessor processor = new ServletProcessor();
processor.process(request, response);
}
else {
StaticResourceProcessor processor = new StaticResourceProcessor();
processor.process(request, response);
}

分析完http请求,把它交给ServletProcessor或者StaticResourceProcessor即可。



第四章 tomcat默认的连接器

第 4 章介绍了 Tomcat 4 的默认连接器。这个连接器已经不推荐使用,推荐使用一个更快的连接器,Coyote。不过,默认的连接器更简单,更易于理解。

在这一章里,即引入了连接器的概念,也引入了容器的概念。咱们慢慢说,先看uml图。


how tomcat works 总结_源码_06


先说连接器,在第三章的简易连接器里,我们只有一个HttpProcessor,在这一章里,我们有了一个Processor连接池,这样的好处就是我们同时可以处理多个请求了!


另一方面,这里在解析请求头的时候,使用的是字符数组来代替字符串。为什么?效率高?效率为什么高?自己看源码找资料。(我怎么觉得自己好赖皮呀)


这里newProcessor与createProcessor的区别在于


newProcessor一定会产生一个新的HttpProcessor;


而createProcessor大部分情况是从processor池中拿;


httpprcessor启动后,(在run方法中)会调用


process(socket);


待通过分析socket,把httprequest填充完毕后,


connector.getContainer().invoke(request, response);


连接器的任务就算是完成了!


这一节的容器是simplecontainer,它的invoke干的事情,其实就是前面几章里ServletProcessor类里process()方法干的事情,通过urlclassloader加载类,调用加载类的service方法。

后面几章的内容,咱们明天接着说。