读书笔记——深入剖析Tomcat

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

本章主要介绍Web服务器是如何运行的。基于Java的Web服务器有两个重要的类:Socket和ServerSocket,本章介绍此二类和HTTP和一个简单的Web服务器。

 

1.1 HTTP

1、是什么:HTTP允许Web服务器和浏览器通过Internet发送并接收数据,是一种基于“请求——响应”的协议。

2、内容

1.HTTP请求:包括请求方法——统一资源标识符(URI)——协议/版本、请求头、请求体。(如图)

URI:指定Internet资源的完整路径。通常被解释为相对于服务器根目录的相对路径。故以“/”开头。URL实际为URI的一种。

请求头:请求头间用CRLF(即回车换行符,\r\n)来分割。请求头和请求行用一个空行分开

读书笔记——深入剖析Tomcat_第1张图片

读书笔记——深入剖析Tomcat_第2张图片

2.HTTP响应:协议——状态码——描述、响应头、响应实体段。

 

读书笔记——深入剖析Tomcat_第3张图片

 

读书笔记——深入剖析Tomcat_第4张图片

 

 

1.2 Socket类

Socket表示客户端套接字。

Sokect,即为套接字。套接字使应用程序可以从网络中读取或写入数据。不同的计算机之间可以通过连接发送或接收字节流,以此达到互相通信的目的。

创建套接字:public Socket(host,port)

1、ServerSocket类

ServerSocket表示服务端套接字,其要等待客户端套接字的连接请求。

创建ServerSokcet:用四个构造函数之一,需要监听的IP地址和监听端口号。(必须),可有backlog(表示传入连接请求的最大队列长度)

IP地址(绑定地址):必须为InetAddress的实例,可用InetAddress.getByName(ip)获得。

 

1.3 应用程序(简易Web服务器)

该程序仅发送位于指定目录的静态资源的请求。

包含三个类,分别为HttpServer,Request,Response。

HttpServer:表示一个Web服务器,负责接收请求并响应请求。其通过Socket获得请求,并将请求封装成Request对象,把解析过后的Request传给Response对象,让Response找到静态资源并返回给客户端。

代码可从书籍给出的网址获取:https://www.brainysoftware.com/download;jsessionid=0C65689E1931A351F6B14844DE9EBF29

 

第二章 一个简单的Servlet容器

Servlet编程需用到 javax.servlet.Servlet和javax.servlet.Http两个包。

2.1 javax.servlet.Servlet接口

1、5个方法

读书笔记——深入剖析Tomcat_第5张图片

init()、service()、destroy()是与Servlet生命周期相关的方法。(调用顺序从前到后)

init():某个servlet被实例化后,容器会调用且仅调用一次init方法来初始化Servlet。init可被重写,也可为空。

service():处理请求的方法。request和response会被传入,在servlet对象的整个生命周期中,service()会被多次调用

destroy():此方法在servlet实例从服务中移除时被调用(servlet容器关闭或servlet容器要释放内存)。当且仅当service()方法中所有线程都退出或执行超时后,才会被调用。此方法让servlet对象有机会去清理自身持有的资源,如内存文件等。该方法被调用后service()方法不会再被调用。

 

2.2 应用程序

此应用程序实现了如下功能:

读书笔记——深入剖析Tomcat_第6张图片

实现的类:

读书笔记——深入剖析Tomcat_第7张图片

该程序还用了门面模式。创建了RequestFacade和ResponseFacade,把真正的requst和response作为私有成员放进facade里面,在facade的方法中调用其方法,防止其他程序员窜改request和response里面的具体处理方法。

 

第三章 连接器

连接器:负责创建request和response实例,并传入servlet中。这意味着连接器还要解析http报文,解析请求头、cookie、请求参数等。

 

3.1 StringManager类

Tomcat中的错误消息处理:错误消息存储在properties文件中,并为了方便管理,将properties放在不同的包下。每个property存储其包下的错误信息。

作用:每个包的一个StringManager处理每个包下的properties文件。(一对用,用单例模式)

读书笔记——深入剖析Tomcat_第8张图片

获取错误消息:getString(错误码)

 

3.2 应用程序

本章应用程序包括连接器模块、启动模块、核心模块。

启动模块:只有一个类Bootstrap。

连接器模块:读书笔记——深入剖析Tomcat_第9张图片

核心模块:ServletProcessor 和 StaticResouceProcessor

 

第四章 Tomcat的默认连接器

该连接器已弃用,被Coyote取代。

默认连接器的优化:1.使用对象池;2.使用字符数组代替字符串。3.实现了HTTP1.1的全部新特性,向下兼容。

 

4.1 HTTP 1.1 新特性

共三个,分别为:持久连接、

 

持久连接

默认使用,也可以显示使用,方法是浏览器发送如下请求头:connection:keep-alive

 

块编码

解决问题:接收方在不知道发送内容长度的情况下,能解析已收到的内容。

实现:HTTP1.1使用名为”transfer-encoding“的请求头,指明字节流会分块发送。每块的结束为\r\n(回车换行符),0\r\n表示事务已经完成。

                            读书笔记——深入剖析Tomcat_第10张图片

 

状态码100

使用HTTP1.1的客户端可以在向服务器发送请求体前发送如下请求头:Expect:100-continue,并等待服务端的确认(HTTP/1.1 100 Continue\r\n)

作用:当客户端发送一个较长的请求体而不确定服务端是否能接收时,可发送此请求头,以避免因拒收而造成较大的网络资源耗费。

 

4.2 Connector 接口

连接器必须要继承org.apache.catalina.Connector 接口,重要方法有4个,getContainer ()、setContainer()、creatRequest()、createResponse().

setContainer:将连接器和某个servlet()关联。

getContainer:获取与当前连接器相关联的servlet容器。

 

4.3 HttpConnector类

将介绍其与第三章不同的新功能,创建服务器套接字、维护HttpProcessor实例、接收HTTP请求服务。

 

创建服务器套接字

HttpConnectorinnitialize()方法会调用一个私有方法open()此方法是从一个服务器套接字工厂获得一个连接,返回一个java.net.ServerSocket实例,赋值给成员变量serverSocket。

 

维护HttpProcessor实例

HttpConnector维护一个HttpProcessor池,避免每次创建和销毁的开销。HttpProcessor实例存储在一个名为processors的java.io.Stack类型变量中:private Stack processors =  new Stack();

minProcessors<=processor的数目<=maxProcessor(两个为int变量)

若希望HttpConnector可持续创建processor,maxProcessor设置为-1

读书笔记——深入剖析Tomcat_第11张图片

 

提供Http请求服务

HttpConnector的主要业务逻辑在run()方法中:该方法包含一个while循环,该循环内服务器套接字等待HTTP请求,直到HttpConnector对象关闭。

具体流程:Http请求——> HttpConnector调用createProcess——>从processors中获得一个processor对象——>若超过最大限度,则返回null,并关闭socket;若没有,执行processor.asssign(socket).(注意,assign()方法是直接返回,而无需等待HttpProcessor实例完成解析,这样才能持续地接收传入的Http请求)

 

4.4 HttpProcessor类

本章着重讲解该类中assign()方法的异步实现,使本类实例可以同时处理多个HTTP请求

1. HttpProcessor实现Runnable接口,让其可以运行在自己的进程中。

2.通过available(布尔变量)、wait()、notifyAll()方法来实现处理器进程和连接器进程的通信。

 

关键方法

void assign(Socket socket):HttpProcessor中的方法,当其接收到新的socket时,使得available=true,然后notifyAll(),唤醒处理器进程。

Socket await():HttpProcessor中的方法, 在run()方法中,当available=false时,阻塞;否则获得socket,并返回socket,让run()方法继续后续处理。

 

具体过程

连接器进程启动(available=false)——>启动处理器进程,调用其assign(socket)方法(此时处理器进程调用了await方法,阻塞中)——>assign唤醒处理器进程——>处理器进程接收socket,并继续执行后续操作。

 

注意点

1.await()使用一个局部变量socket,不直接将成员变量socket返回:可以在当前Socket对象完成之前,继续接收下一个Socket对象。

2.await()方法为何需要调用notifiyAll():防止出现,另一个Socket对象已经到达,而此时变量available的值还是true的情况。在此情况下,连接器线程会在assign()内阻塞,知道处理器线程调用notifyAll()。

 

第五章 Servlet容器

(本章只是看了,没有实现容器,不知道connnector是在什么时候、如何把servlet容器启动起来的)

servlet容器用于处理请求servlet资源,并为Web客户端填充response对象的模块。其为....catalina.Container接口的实例。Tomcat中共有Engine、Host、Wrapper、Context四种容器,本章讲解Context和Wrapper。

Engine:表示整个Catalina servlet引擎;

Host:表示包含有一个或多个Context容器的虚拟主机;

Context:表示一个Web应用程序,一个Context可用多个Wrapper;

Wrapper:表示一个单独的servlet。

 

5.1 Container容器

1.一个容器可以用0个或多个低层级别的子容器。

对子容器的操作:addChild(Container child)、removeChild((Container child)、findChild((Container child)、findChildren()等。

 

2. 容器可以包含一些支持的组件,如载入器、记录器、管理器、领域和资源等。其提供了getter和setter方法将组件和容器关联起来。

对组件的操作:get\setLoader()、get\setLogger()等。

PS:Tomcat管理员还可通过配置文件(server.xml)来决定使用哪种容器。这是通过引入容器中的管道和阀的集合实现的。

 

5.2 管道任务

该节旨在说明当连接器调用了servlet容器的invoke()方法后发生了什么。然后在对应小节中讨论Pineline、Value、ValueContext、Contained四个相关接口。

 

管道

其包含servlet容器中将要被调用的任务。一个阀指一个具体的任务。阀的数量不包括基础阀。

                       读书笔记——深入剖析Tomcat_第12张图片

工作机制:一个servlet对应一条管道。调用了容器的invoke()后,容器将处理任务交给管道,管道从第一个阀开始处理,直到所有阀处理完成。基础阀在最后处理。

 

5.2.1 Pipeline接口

             读书笔记——深入剖析Tomcat_第13张图片

invoke():处理阀

get/setBasic():获取/设置基础阀

add/get/remove Values():增加/获取/移除 阀

5.2.2  Value接口

阀是Value的实例,用来处理接收到的请求。

       读书笔记——深入剖析Tomcat_第14张图片

invoke():处理阀

getInfo():返回阀的具体信息

 

5.2.3 ValueContext接口

            读书笔记——深入剖析Tomcat_第15张图片

invokeNext():处理下一个阀

getInfo():返回ValueContext的实现信息

 

5.2.4 Contained接口

阀可以选择是否实现此接口,该接口的实现类可以通过接口中的方法至多与一个servlet容器相关联。

             读书笔记——深入剖析Tomcat_第16张图片

 

5.3 Wrapper接口

Wrapper接口的实现类负责管理其基础servlet类的servlet生命周期,即调用servlet的init()、service()、destroy()等方法。其为最低级的servlet容器。

重要方法:load()、allocation()

allocate():分配一个已经初始化的servlet实例

load():载入并初始化servlet类

 

5.4 Context接口

重要方法:addWrapper()、createWrapper()。

 

 

第六章 生命周期

本章介绍通过Lifecycle、LifecycleEvent和LifecycleListener及工具类lifecycleSupport来管理生命周期的方法。

 

6.1 Lifecycle接口

Catalina允许一个组件包含其他组件。故Catalina的组件只要启动一个,就可启动全部。这种单一启动/关闭机制是通过Lifecycle接口实现的。每个父组件启动后,会去寻找其子组件,并逐个启用start()/stop()方法。

                         读书笔记——深入剖析Tomcat_第17张图片

重要方法:statrt()、stop()。供其父组件使用,实现对其进行启动/关闭操作。

最上面三个方法:与事件监听器相关。

 

6.2 LifecycleEvent类

生命周期事件是其的实例。

 读书笔记——深入剖析Tomcat_第18张图片

 

 

6.3LifecycleListener接口

生命周期事件监听器为其实例。

              

其唯一方法为lifecycleEvent(),当事件监听器监听到某事件发生,会调用此方法。

 

6.4 LifecycleSupport类

其帮助组件管理监听器,并触发相应的生命周期事件。所有的监听器都会被放进listeners数组进行统一管理。

  读书笔记——深入剖析Tomcat_第19张图片

 

第七章 日志记录器

其为记录消息的组件,需要与某个Servlet容器相关联。

第八章 载入器

第九章 Session管理

第十章 安全性

第十一章 StandardWrapper

第十二章 StandardConctext类

第十三章 Host和Engine

第十四章 服务器组件和服务组件

第十五章 Digester库

第十六章 关闭钩子 

第十七章 启动Tomcat

第十八章 部署器

第十九章 Manage应用程序的Servlet类

第二十章 基于JMX的管理

 

你可能感兴趣的:(文章阅读)