Tomcat内部工作原理讲解.doc

上传人:99****p 文档编号:1440892 上传时间:2019-02-27 格式:DOC 页数:71 大小:516KB
下载 相关 举报
Tomcat内部工作原理讲解.doc_第1页
第1页 / 共71页
Tomcat内部工作原理讲解.doc_第2页
第2页 / 共71页
Tomcat内部工作原理讲解.doc_第3页
第3页 / 共71页
Tomcat内部工作原理讲解.doc_第4页
第4页 / 共71页
Tomcat内部工作原理讲解.doc_第5页
第5页 / 共71页
点击查看更多>>
资源描述

1、 Tomcat 内部工作原理讲解概要 欢迎阅读How Tomcat Works这本书。这本书解剖了 Tomcat4.1.12 和 5.0.18 版本,解释了它的 servlet 容器的内部运行机制,那是一个免费的,开源的, 最受欢迎的 servlet 容器,代号为Catalina。Tomcat 是一个复杂的系统,由许多不同的组件构成。那些想要学习 Tomcat 运行机制的朋友 大部分知道从何入手。这本书会提供一个蓝图,然后为每一个组件构造一个简化版本,使得可以更加容易的理解这些组件。在这之后才会对真实的组件进行解释。 你应该从这份简介开始阅读,因为它解释了这本书的结构,同时给你勾画了这个项目构

2、造的简洁轮廓。“准备前提软件”这一节会给你一些指示,例如你需要下载什 么样的软件,如何为你的代码创建目录结构等等。 本书为谁而作 这本书是为任何一个使用 Java 技术进行工作的人而准备的。 假如你是一个 servlet/jsp 程序员或者一个 Tomcat 用户,而且对一个 servlet 容器是如何工作这个问题你感兴趣的话,这本书就是为你准备 的。 假如你想加入 Tomcat 的开发团队的话,这本书就是为你准备的,因为你首先需要学习那些已存在的代码是如何工作的。 假如你从未涉及 web 开发,但你对一般意义上的软件开发感兴趣的话,你可以在这本书学到一个像 Tomcat 一样的大型项目是如何

3、进行设计和开发的。 假如你想配置和自定义 Tomcat,你也应该读读这本书。 为了理解书中的讨论,你需要了解 Java 面向对象编程技术以及 servlet 编程。假如你对这些不熟悉的话,这里有很多书籍可以参考,包括 Budi 的 Java for the Web with Servlets, JSP, and EJB。为了让这些材料更容易理解,每一章开始都会有便于理解所讨论主题的必要的背景资料介绍。 Servlet 容器是如何工作的 servlet 容器是一个复杂的系统。不过,一个 servlet 容器要为一个 servlet 的请求提供服务,基本上有三件事要做: 创建一个 request

4、对象并填充那些有可能被所引用的 servlet 使用的信息,如参数、头部、cookies、查询字符串、URI 等等。一个 request 对象是 javax.servlet.ServletRequest 或javax.servlet.http.ServletRequest 接口的一个实例。 创建一个 response 对象,所引用的 servlet 使用它来给客户端发送响应。一个 response 对象 javax.servlet.ServletResponse 或 javax.servlet.http.ServletResponse 接口的一个实例。 调用 servlet 的 service

5、 方法,并传入 request 和 response 对象。在这里 servlet 会从request 对象取值,给 response 写值。 当你读这些章节的时候,你将会找到关于 catalina servlet 容器的详细讨论。 Catalina 架构图 Catalina 是一个非常复杂的,并优雅的设计开发出来的软件,同时它也是模块化的。基于“Servlet 容器是如何工作的”这一节中提到的任务,你可 以把 Catalina 看成是由两个主要模块所组成的:连接器(connector)和容器(container)。在 Figure I.1 中的架构图,当然是简化了。在稍后的章节里边,你将会一

6、个个的揭开所有更小的组件的神秘面纱。 现在重新回到 Figure I.1,连接器是用来“连接”容器里边的请求的。它的工作是为接收到每一个 HTTP 请求构造一个 request 和 response 对象。然后它把流程传递 给容器。容器从连接器接收到 requset 和 response 对象之后调用 servlet 的 service 方法用于响应。谨记,这个描述仅仅是冰山一角而 已。这里容器做了相当多事情。例如,在它调用 servlet 的 service 方法之前,它必须加载这个 servlet,验证用户(假如需要的话),更新用 户会话等等。一个容器为了处理这个进程使用了很多不同的模块,

7、这也并不奇怪。例如,管理模块是用来处理用户会话,而加载器是用来加载servlet 类等 等。 Tomcat 4 和 5 这本书涵盖了 Tomcat4 和 5.这两者有一些不同之处: Tomcat 5 支持 Servlet 2.4 和 JSP 2.0 规范,而 Tomcat 4 支持 Servlet 2.3 和 JSP 1.2。 比起 Tomcat 4,Tomcat 5 有一些更有效率的默认连接器。 Tomcat 5 共享一个后台处理线程,而 Tomcat 4 的组件都有属于自己的后台处理线程。因此,就这一点而言,Tomcat 5 消耗较少的资源。 Tomcat 5 并不需要一个映射组件(map

8、per component)用于查找子组件,因此简化了代码。 各章概述 这本书共 20 章,其中前面两章作为导言。 第 1 章说明一个 HTTP 服务器是如何工作的,第 2 章突出介绍了一个简单的 servlet 容器。接下来的两章关注连接器,第 5 章到第 20 章涵盖容器里边的每 一个组件。以下是各章节的摘要。 注意:对于每个章节,会有一个附带程序,类似于正在被解释的组件。 第 1 章从这本书一开始就介绍了一个简单的 HTTP 服务器。要建立一个可工作的 HTTP 服务器,你需要知道在 包里边的 2 个类的内部运 作:Socket 和 ServerSocket。这里有关于这 2 个类足够

9、的背景资料,使得你能够理解附带程序是如何工作的。 第 2 章说明简单的 servlet 容器是如何工作的。这一章带有 2 个 servlet 容器应用,可以处理静态资源和简单的 servlet 请求。尤其是你将会学 到如何创建 request 和 response 对象,然后把它们传递给被请求的 servlet 的 service 方法。在 servlet 容器里边还有一个 servlet,你可以从一个 web 浏览器中调用它。 第 3 章介绍了一个简化版本的 Tomcat 4 默认连接器。这章里边的程序提供了一个学习工具,用于理解第 4 章里边的讨论的连接器。 第 4 章介绍了 Tomcat

10、 4 的默认连接器。这个连接器已经不推荐使用,推荐使用一个更快的连接器,Coyote。不过,默认的连接器更简单,更易于理解。 第 5 章讨论 container 模块。container 指的是 org.apache.catalina.Container 接口,有 4种类型的 container:engine, host, context 和 wrapper。这章提供了两个工作于 context 和wrapper 的程序。 第 6 章解释了 Lifecycle 接口。这个接口定义了一个 Catalina 组件的生命周期,并提供了一个优雅的方式,用来把在该组件发生的事件通知其他组 件。另外,Li

11、fecycle 接口提供了一个优雅的机制,用于在 Catalina 通过单一的 start/stop 来启动和停止组件 第 7 章包括日志,该组件是用来记录错误信息和其他信息的。 第 8 章解释了加载器(loader)。加载器是一个重要的 Catalina 模块,负责加载 servlet 和一个web 应用所需的其他类。这章还展示了如何 实现应用的重新加载。 第 9 章讨论了管理器(manager)。这个组件用来管理会话管理中的会话信息。它解释了各式各样类型的管理器,管理器是如何把会话对象持久化的。在章 末,你将会学到如何创建一个的应用,该应用使用 StandardManager 实例来运行一

12、个使用会话对象进行储值的 servlet。 第 10 章包括 web 应用程序安全性的限制,用来限制进入某些内容。你将会学习与安全相关的实体,例如 主角(principals),角色(roles),登陆配置,认证等等。你也将会写两个程序,它们在StandardContext 对象中安装一个身份 验证阀(authenticator valve)并且使用了基本的认证来对用户进行认证。 第 11 章详细解释了在一个 web 应用中代表一个 servlet 的org.apache.catalina.core.StandardWrapper 类。 特别的是,这章解释了过滤器(filter)和一个serv

13、let 的 service 方法是怎样给调用的。这章的附带程序使用 StandardWrapper 实例来代表servlet。 第 12 章包括了在一个 web 应用中代表一个 servlet 的org.apache.catalina.core.StandardContext 类。特别 是这章讨论了一个 StandardContext 对象是如何给配置的,对于每个传入的 HTTP 请求在它里面会发生什么,是怎样支持自动重新加载的,还有就 是,在一个在其相关的组件中执行定期任务的线程中,Tomcat 5 是如何共享的。 第 13 章介绍了另外两个容器:host 和 engine。你也同样可以找到

14、这两个容器的标准实 现:org.apache.catalina.core.StandardHost 和 org.apache.catalina.core.StandardEngine。 第 14 章提供了服务器和服务组件的部分。服务器为整个 servlet 容器提供了一个优雅的启动和停止机制,而服务为容器和一个或多个连接器提供了一个支 架。这章附带的程序说明了如何使用服务器和服务。 第 15 章解释了通过 Digester 来配置 web 应用。Digester 是来源于 Apache 软件基金会的一个令人振奋的开源项目。对那些尚未初步了解的 人,这章通过一节略微介绍了 Digester 库以

15、及 XML文件中如何使用它来把节点转换为 Java 对象。然后解释了用来配置一个 StandardContext 实例的ContextConfig 对象。 第 16 章解释了 shutdown 钩子,Tomcat 使用它总能获得一个机会用于 clean-up,而无论用户是怎样停止它的(即适当的发送一个 shutdown 命令或者不适当的简单关闭控制台)。 第 17 章讨论了通过批处理文件和 shell 脚本对 Tomcat 进行启动和停止。 第 18 章介绍了部署工具(deployer),这个组件是负责部署和安装 web 应用的。 第 19 章讨论了一个特殊的接口,ContainerServl

16、et,能够让 servlet 访问 Catalina 的内部对象。特别是,它讨论了 Manager 应用,你可以通过它来部署应用程序。 第 20 章讨论了 JMX 以及 Tomcat 是如何通过为其内部对象创建 MBeans 使得这些对象可管理的。 各章的程序 每一章附带了一个或者多个程序,侧重于 Catalina 的一个特定的组件。通常你可以找到这些简化版本,无论是正在被解释的组件或者解释如何使用 Catalina 组件的代码。各章节的程序的所有的类和接口都放在 ex章节号.pyrmont 包或者它的子包。例如第 1 章的程序的类就是放在 ex01.pyrmont 包中。 准备的前提软件 这

17、本书附带的程序运行于 J2SE1.4 版本。压缩源文件可以从作者的网站 中 下载。它包括 Tomcat 4.1.12 和这本书所使用的程序的源代码。假设你已经安装了 J2SE 1.4 并且你的 path 环境变量中已经包括了 JDK 的安装目录,请按照下列步骤: 1. 解压缩 ZIP 文件。所有的解压缩文件将放在一个新的目录 howtomcatworks 中。howtomcatworks 将是你的工作目录。在 howtomcatworks 目录下面将会有数个子目录,包括lib (包括所有所需的库),src (包括所有的源文件),webroot (包括一个 HTML 文件和三个servlet 样

18、本),和 webapps (包括示例应用程序)。 2. 改变目录到工作目录下并编译 java 文件。加入你使用的是 Windows,运行 win-compile.bat文件。假如你的计算机是 Linux 机器,敲 入以下内容:(如有必要的话不用忘记使用 chmod更改文件属性) ./linux-compile.sh 注意:你可以在 ZIP 文件中的 Readme.txt 文件找到更多信息。 第一章:一个简单的 Web 服务器 本章说明 java web 服务器是如何工作的。Web 服务器也成为超文本传输协议(HTTP)服务器,因为它使用 HTTP 来跟客户端进行通信的,这通常是个 web 浏览

19、器。一 个基于 java 的 web 服务器使用两个重要的类:.Socket 和 .ServerSocket,并通过 HTTP 消息进行 通信。因此这章就自然是从 HTTP 和这两个类的讨论开始的。接下去,解释这章附带的一个简单的 web 服务器。 超文本传输协议(HTTP) HTTP 是一种协议,允许 web 服务器和浏览器通过互联网进行来发送和接受数据。它是一种请求和响应协议。客户端请求一个文件而服务器响应请求。HTTP 使用可靠的 TCP 连接-TCP 默认使用 80端口。第一个 HTTP 版是 HTTP/0.9,然后被 HTTP/1.0 所替代。正在取代 HTTP/1.0 的是当 前版

20、本HTTP/1.1,它定义于征求意见文档(RFC) 2616,可以从http:/www.w3.org/Protocols/HTTP/1.1/rfc2616.pdf 下 载。 注意:本节涵盖的 HTTP 1.1 只是简略的帮助你理解 web 服务器应用发送的消息。假如你对更多详细信息感兴趣,请阅读 RFC 2616。 在 HTTP 中,始终都是客户端通过建立连接和发送一个 HTTP 请求从而开启一个事务。web 服务器不需要联系客户端或者对客户端做一个回调连接。无论是客 户端或者服务器都可以提前终止连接。举例来说,当你正在使用一个 web 浏览器的时候,可以通过点击浏览器上的停止按钮来停止一个文

21、件的下载进程,从而有效 的关闭与 web 服务器的 HTTP 连接。 HTTP 请求 一个 HTTP 请求包括三个组成部分: 方法统一资源标识符(URI)协议/版本 请求的头部 主体内容 下面是一个 HTTP 请求的例子: POST /examples/default.jsp HTTP/1.1Accept: text/plain; text/htmlAccept-Language: en-gbConnection: Keep-AliveHost: localhostUser-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)Conten

22、t-Length: 33Content-Type: application/x-www-form-urlencodedAccept-Encoding: gzip, deflatelastName=Franks一旦你成功创建了一个 Socket 类的实例,你可以使用它来发送和接受字节流。要发送字节流,你首先必须调用 Socket 类的 getOutputStream 方法来获取一个 java.io.OutputStream 对象。要发送文本到一个远程应用,你经常要从返回的 OutputStream 对象中构造一个 java.io.PrintWriter对象。要从连接的另一端接受字节流,你可以调用

23、 Socket 类的 getInputStream 方法用来返回一个java.io.InputStream 对象。以下的代码片段创建了一个套接字,可以和本地 HTTP 服务器(127.0.0.1 是指本地主机)进行通讯,发送一个 HTTP 请求,并从服务器接受响应。它 创建了一个 StringBuffer 对象来保存响应并在控制台上打印出来。Socket socket = new Socket(“127.0.0.1“, “8080“);OutputStream os = socket.getOutputStream();boolean autoflush = true;PrintWriter

24、out = new PrintWriter(socket.getOutputStream(), autoflush);BufferedReader in = new BufferedReader(new InputStreamReader( socket.getInputstream() );/ send an HTTP request to the web serverout.println(“GET /index.jsp HTTP/1.1“);out.println(“Host: localhost:8080“);out.println(“Connection: Close“);out.p

25、rintln();/ read the responseboolean loop = true;StringBuffer sb = new StringBuffer(8096);while (loop) if ( in.ready() ) int i=0;while (i!=-1) i = in.read();sb.append(char) i);loop = false;Thread.currentThread().sleep(50);/ display the response to the out consoleSystem.out.println(sb.toString();socke

26、t.close();请注意,为了从 web 服务器获取适当的响应,你需要发送一个遵守 HTTP 协议的 HTTP 请求。假如你已经阅读了前面一节超文本传输协议(HTTP),你应 该能够理解上面代码提到的 HTTP 请求。注意:你可以本书附带的 com.brainysoftware.pyrmont.util.HttpSniffer 类来发送一个 HTTP请求并显示响应。要使用这个 Java 程 序,你必须连接到互联网上。虽然它有可能并不会起作用,假如你有设置防火墙的话。ServerSocket 类 Socket 类代表一个客户端套接字,即任何时候你想连接到一个远程服务器应用的时候你构造的套接字,

27、现在,假如你想实施一个服务器应用,例如一个 HTTP 服务器或者 FTP 服务器,你需要一种不同的做法。这是因为你的服务器必须随时待命,因为它不知道一个客户端应用什么时候会尝试去连接它。为了让你 的应用能随时待命,你需要使用 .ServerSocket 类。这是服务器套接字的实现。ServerSocket 和 Socket 不同,服务器套接字的角色是等待来自客户端的连接请求。一旦服务器套接字获得一个连接请求,它创建一个 Socket 实例来与客户端进行通信。要创建一个服务器套接字,你需要使用 ServerSocket 类提供的四个构造方法中的一个。你需要指定 IP 地址和服务器套接字将要进行监

28、听的端口号。通 常,IP 地址将会是 127.0.0.1,也就是说,服务器套接字将会监听本地机器。服务器套接字正在监听的 IP 地址被称为是绑定地址。服务器套接字的另一 个重要的属性是 backlog,这是服务器套接字开始拒绝传入的请求之前,传入的连接请求的最大队列长度。其中一个 ServerSocket 类的构造方法如下所示:public ServerSocket(int port, int backLog, InetAddress bindingAddress);对于这个构造方法,绑定地址必须是 .InetAddress 的一个实例。一种构造InetAddress 对象的简单的方法是调用它

29、的静态 方法 getByName,传入一个包含主机名称的字符串,就像下面的代码一样。InetAddress.getByName(“127.0.0.1“);下面一行代码构造了一个监听的本地机器 8080 端口的 ServerSocket,它的 backlog 为 1。new ServerSocket(8080, 1, InetAddress.getByName(“127.0.0.1“);一旦你有一个 ServerSocket 实例,你可以让它在绑定地址和服务器套接字正在监听的端口上等待传入的连接请求。你可以通过调用 ServerSocket 类的 accept 方法做到这点。这个方法只会在有连接

30、请求时才会返回,并且返回值是一个 Socket 类的实例。Socket 对象 接下去可以发送字节流并从客户端应用中接受字节流,就像前一节“Socket 类“解释的那样。实际上,这章附带的程序中,accept 方法是唯一用到的方 法。应用程序 我们的 web 服务器应用程序放在 ex01.pyrmont 包里边,由三个类组成: HttpServer Request Response 这个应用程序的入口点(静态 main 方法)可以在 HttpServer 类里边找到。main 方法创建了一个HttpServer 的实例并调用了它的 await 方法。await 方法,顾名思义就是在一个指定的端口

31、上等待HTTP 请求,处理它们并发送响应返回客户端。它一直等待直至接收到 shutdown 命令。应用程序不能做什么,除了发送静态资源,例如放在一个特定目录的 HTML 文件和图像文件。它也在控制台上显示传入的 HTTP 请求的字节流。不过,它不给浏 览器发送任何的头部例如日期或者cookies。现在我们将在以下各小节中看看这三个类。HttpServer 类 HttpServer 类代表一个 web 服务器并展示在 Listing 1.1 中。请注意,await 方法放在Listing 1.2 中,为了节省空间没有重复放在 Listing 1.1 中。Listing 1.1: HttpServ

32、er 类package ex01.pyrmont;import .Socket;import .ServerSocket;import .InetAddress;import java.io.InputStream;import java.io.OutputStream;import java.io.IOException;import java.io.File;public class HttpServer /* WEB_ROOT is the directory where our HTML and other files reside.* For this package, WEB_RO

33、OT is the “webroot“ directory under the* working directory.* The working directory is the location in the file system* from where the java command was invoked.*/public static final String WEB_ROOT =System.getProperty(“user.dir“) + File.separator + “webroot“;/ shutdown commandprivate static final Str

34、ing SHUTDOWN_COMMAND = “/SHUTDOWN“;/ the shutdown command receivedprivate boolean shutdown = false;public static void main(String args) HttpServer server = new HttpServer();server.await();public void await() .Listing 1.2: HttpServer 类的 await 方法 public void await() ServerSocket serverSocket = null;in

35、t port = 8080;try serverSocket = new ServerSocket(port, 1,InetAddress.getByName(“127.0.0.1“);catch (IOException e) e.printStackTrace();System.exit(1);/ Loop waiting for a requestwhile (!shutdown) Socket socket = null;InputStream input = null;OutputStream output = null;try socket = serverSocket.accep

36、t();input = socket.getInputStream();output = socket.getOutputStream();/ create Request object and parseRequest request = new Request(input);request.parse();/ create Response objectResponse response = new Response(output);response.setRequest(request);response.sendStaticResource();/ Close the socketso

37、cket.close();/check if the previous URI is a shutdown commandshutdown = request.getUri().equals(SHUTDOWN_COMMAND);catch (Exception e) e.printStackTrace ();continue;web 服务器能提供公共静态 final 变量 WEB_ROOT 所在的目录和它下面所有的子目录下的静态资源。如下所示,WEB_ROOT 被初始化:public static final String WEB_ROOT =System.getProperty(“user.

38、dir“) + File.separator + “webroot“;代码列表包括一个叫 webroot 的目录,包含了一些你可以用来测试这个应用程序的静态资源。你同样可以在相同的目录下找到几个 servlet 用于测试下 一章的应用程序。为了请求一个静态资源,在你的浏览器的地址栏或者网址框里边敲入以下的 URL:http:/machineName:port/staticResource如果你要从一个不同的机器上发送请求到你的应用程序正在运行的机器上,machineName 应该是正在运行应用程序的机器的名称或者 IP 地址。假如你的 浏览器在同一台机器上,你可以使用localhost 作为

39、machineName。端口是 8080,staticResource 是你需要请求的文件的名 称,且必须位于 WEB_ROOT 里边。举例来说,假如你正在使用同一台计算机上测试应用程序,并且你想要调用 HttpServer 对象去发送一个 index.html 文件,你可以使用一下的 URL:http:/localhost:8080/index.html要停止服务器,你可以在 web 浏览器的地址栏或者网址框里边敲入预定义字符串,就在 URL 的host:port 的后面,发送一个 shutdown 命令。 shutdown 命令是在 HttpServer 类的静态 final 变量SHUTDOWN 里边定义的:private static final String SHUTDOWN_COMMAND = “/SHUTDOWN“;因此,要停止服务器,使用下面的 URL:http:/localhost:8080/SHUTDOWN现在我们来看看 Listing 1.2 印出来的 await 方法。使用方法名 await 而不是 wait 是因为 wait 方法是与线程相关的 java.lang.Object 类的一个重要方法。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 实用文档资料库 > 策划方案

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。