Tomcat内部工作原理讲解

上传人:gbs****77 文档编号:9908449 上传时间:2020-04-08 格式:DOC 页数:71 大小:516KB
返回 下载 相关 举报
Tomcat内部工作原理讲解_第1页
第1页 / 共71页
Tomcat内部工作原理讲解_第2页
第2页 / 共71页
Tomcat内部工作原理讲解_第3页
第3页 / 共71页
点击查看更多>>
资源描述
Tomcat 内部工作原理讲解 概要 欢迎阅读 How Tomcat Works 这本书 这本书解剖了 Tomcat4 1 12 和 5 0 18 版本 解释了 它的 servlet 容器的内部运行机制 那是一个免费的 开源的 最受欢迎的 servlet 容器 代号为 Catalina Tomcat 是一个复杂的系统 由许多不同的组件构成 那些想要学习 Tomcat 运行机制的 朋友 大部分知道从何入手 这本书会提供一个蓝图 然后为每一个组件构造一个简化版本 使得可 以更加容易的理解这些组件 在这之后才会对真实的组件进行解释 你应该从这份简介开始阅读 因为它解释了这本书的结构 同时给你勾画了这个项目构造的简 洁轮廓 准备前提软件 这一节会给你一些指示 例如你需要下载什 么样的软件 如何为你的代 码创建目录结构等等 本书为谁而作 这本书是为任何一个使用 Java 技术进行工作的人而准备的 假如你是一个 servlet jsp 程序员或者一个 Tomcat 用户 而且对一个 servlet 容器是如何工 作这个问题你感兴趣的话 这本书就是为你准备 的 假如你想加入 Tomcat 的开发团队的话 这本书就是为你准备的 因为你首先需要学习那些已 存在的代码是如何工作的 假如你从未涉及 web 开发 但你对一般意义上的软件开发感兴趣的话 你可以在这本书学到 一个像 Tomcat 一样的大型项目是如何进行设计和开发的 假如你想配置和自定义 Tomcat 你也应该读读这本书 为了理解书中的讨论 你需要了解 Java 面向对象编程技术以及 servlet 编程 假如你对这些不 熟悉的话 这里有很多书籍可以参考 包括 Budi 的 Java for the Web with Servlets JSP and EJB 为了让这些材料更容易理解 每一章开始都会有便于理解所讨论主题的必要的背景资料 介绍 Servlet 容器是如何工作的 servlet 容器是一个复杂的系统 不过 一个 servlet 容器要为一个 servlet 的请求提供服务 基本上有三件事要做 创建一个 request 对象并填充那些有可能被所引用的 servlet 使用的信息 如参数 头部 cookies 查询字符串 URI 等等 一个 request 对象是 javax servlet ServletRequest 或 javax servlet http ServletRequest 接口的一个实例 创建一个 response 对象 所引用的 servlet 使用它来给客户端发送响应 一个 response 对 象 javax servlet ServletResponse 或 javax servlet http ServletResponse 接口的一个 实例 调用 servlet 的 service 方法 并传入 request 和 response 对象 在这里 servlet 会从 request 对象取值 给 response 写值 当你读这些章节的时候 你将会找到关于 catalina servlet 容器的详细讨论 Catalina 架构图 Catalina 是一个非常复杂的 并优雅的设计开发出来的软件 同时它也是模块化的 基于 Servlet 容器是如何工作的 这一节中提到的任务 你可 以把 Catalina 看成是由两个主要模块 所组成的 连接器 connector 和容器 container 在 Figure I 1 中的架构图 当然是简化了 在 稍后的章节里边 你将会一个个的揭开所有更小的组件的神秘面纱 现在重新回到 Figure I 1 连接器是用来 连接 容器里边的请求的 它的工作是为接收到每 一个 HTTP 请求构造一个 request 和 response 对象 然后它把流程传递 给容器 容器从连接器接收 到 requset 和 response 对象之后调用 servlet 的 service 方法用于响应 谨记 这个描述仅仅是冰 山一角而 已 这里容器做了相当多事情 例如 在它调用 servlet 的 service 方法之前 它必须加 载这个 servlet 验证用户 假如需要的话 更新用 户会话等等 一个容器为了处理这个进程使用 了很多不同的模块 这也并不奇怪 例如 管理模块是用来处理用户会话 而加载器是用来加载 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 并不需要一个映射组件 mapper component 用于查找子组件 因此简化了代码 各章概述 这本书共 20 章 其中前面两章作为导言 第 1 章说明一个 HTTP 服务器是如何工作的 第 2 章突出介绍了一个简单的 servlet 容器 接下 来的两章关注连接器 第 5 章到第 20 章涵盖容器里边的每 一个组件 以下是各章节的摘要 注意 对于每个章节 会有一个附带程序 类似于正在被解释的组件 第 1 章从这本书一开始就介绍了一个简单的 HTTP 服务器 要建立一个可工作的 HTTP 服务器 你需要知道在 包里边的 2 个类的内部运 作 Socket 和 ServerSocket 这里有关于这 2 个 类足够的背景资料 使得你能够理解附带程序是如何工作的 第 2 章说明简单的 servlet 容器是如何工作的 这一章带有 2 个 servlet 容器应用 可以处理 静态资源和简单的 servlet 请求 尤其是你将会学 到如何创建 request 和 response 对象 然后把 它们传递给被请求的 servlet 的 service 方法 在 servlet 容器里边还有一个 servlet 你可以从 一个 web 浏览器中调用它 第 3 章介绍了一个简化版本的 Tomcat 4 默认连接器 这章里边的程序提供了一个学习工具 用 于理解第 4 章里边的讨论的连接器 第 4 章介绍了 Tomcat 4 的默认连接器 这个连接器已经不推荐使用 推荐使用一个更快的连接 器 Coyote 不过 默认的连接器更简单 更易于理解 第 5 章讨论 container 模块 container 指的是 org apache catalina Container 接口 有 4 种类型的 container engine host context 和 wrapper 这章提供了两个工作于 context 和 wrapper 的程序 第 6 章解释了 Lifecycle 接口 这个接口定义了一个 Catalina 组件的生命周期 并提供了一个 优雅的方式 用来把在该组件发生的事件通知其他组 件 另外 Lifecycle 接口提供了一个优雅的 机制 用于在 Catalina 通过单一的 start stop 来启动和停止组件 第 7 章包括日志 该组件是用来记录错误信息和其他信息的 第 8 章解释了加载器 loader 加载器是一个重要的 Catalina 模块 负责加载 servlet 和一个 web 应用所需的其他类 这章还展示了如何 实现应用的重新加载 第 9 章讨论了管理器 manager 这个组件用来管理会话管理中的会话信息 它解释了各式各样 类型的管理器 管理器是如何把会话对象持久化的 在章 末 你将会学到如何创建一个的应用 该 应用使用 StandardManager 实例来运行一个使用会话对象进行储值的 servlet 第 10 章包括 web 应用程序安全性的限制 用来限制进入某些内容 你将会学习与安全相关的实 体 例如 主角 principals 角色 roles 登陆配置 认证等等 你也将会写两个程序 它们在 StandardContext 对象中安装一个身份 验证阀 authenticator valve 并且使用了基本的认证来对 用户进行认证 第 11 章详细解释了在一个 web 应用中代表一个 servlet 的 org apache catalina core StandardWrapper 类 特别的是 这章解释了过滤器 filter 和一个 servlet 的 service 方法是怎样给调用的 这章的附带程序使用 StandardWrapper 实例来代表 servlet 第 12 章包括了在一个 web 应用中代表一个 servlet 的 org apache catalina core StandardContext 类 特别 是这章讨论了一个 StandardContext 对象 是如何给配置的 对于每个传入的 HTTP 请求在它里面会发生什么 是怎样支持自动重新加载的 还 有就 是 在一个在其相关的组件中执行定期任务的线程中 Tomcat 5 是如何共享的 第 13 章介绍了另外两个容器 host 和 engine 你也同样可以找到这两个容器的标准实 现 org apache catalina core StandardHost 和 org apache catalina core StandardEngine 第 14 章提供了服务器和服务组件的部分 服务器为整个 servlet 容器提供了一个优雅的启动和 停止机制 而服务为容器和一个或多个连接器提供了一个支 架 这章附带的程序说明了如何使用服 务器和服务 第 15 章解释了通过 Digester 来配置 web 应用 Digester 是来源于 Apache 软件基金会的一个 令人振奋的开源项目 对那些尚未初步了解的 人 这章通过一节略微介绍了 Digester 库以及 XML 文件中如何使用它来把节点转换为 Java 对象 然后解释了用来配置一个 StandardContext 实例的 ContextConfig 对象 第 16 章解释了 shutdown 钩子 Tomcat 使用它总能获得一个机会用于 clean up 而无论用户是 怎样停止它的 即适当的发送一个 shutdown 命令或者不适当的简单关闭控制台 第 17 章讨论了通过批处理文件和 shell 脚本对 Tomcat 进行启动和停止 第 18 章介绍了部署工具 deployer 这个组件是负责部署和安装 web 应用的 第 19 章讨论了一个特殊的接口 ContainerServlet 能够让 servlet 访问 Catalina 的内部对 象 特别是 它讨论了 Manager 应用 你可以通过它来部署应用程序 第 20 章讨论了 JMX 以及 Tomcat 是如何通过为其内部对象创建 MBeans 使得这些对象可管理的 各章的程序 每一章附带了一个或者多个程序 侧重于 Catalina 的一个特定的组件 通常你可以找到这些简 化版本 无论是正在被解释的组件或者解释如何使用 Catalina 组件的代码 各章节的程序的所有 的类和接口都放在 ex 章节号 pyrmont 包或者它的子包 例如第 1 章的程序的类就是放在 ex01 pyrmont 包中 准备的前提软件 这本书附带的程序运行于 J2SE1 4 版本 压缩源文件可以从作者的网站 中 下载 它包括 Tomcat 4 1 12 和这本书所使用的程序的源代码 假设 你已经安装了 J2SE 1 4 并且你的 path 环境变量中已经包括了 JDK 的安装目录 请按照下列步骤 1 解压缩 ZIP 文件 所有的解压缩文件将放在一个新的目录 howtomcatworks 中 howtomcatworks 将是你的工作目录 在 howtomcatworks 目录下面将会有数个子目录 包括 lib 包括所有所需的库 src 包括所有的源文件 webroot 包括一个 HTML 文件和三个 servlet 样本 和 webapps 包括示例应用程序 2 改变目录到工作目录下并编译 java 文件 加入你使用的是 Windows 运行 win compile bat 文件 假如你的计算机是 Linux 机器 敲 入以下内容 如有必要的话不用忘记使用 chmod 更改文件属性 linux compile sh 注意 你可以在 ZIP 文件中的 Readme txt 文件找到更多信息 第一章 一个简单的 Web 服务器 本章说明 java web 服务器是如何工作的 Web 服务器也成为超文本传输协议 HTTP 服务器 因 为它使用 HTTP 来跟客户端进行通信的 这通常是个 web 浏览器 一 个基于 java 的 web 服务器使用 两个重要的类 Socket 和 ServerSocket 并通过 HTTP 消息进行 通信 因此这 章就自然是从 HTTP 和这两个类的讨论开始的 接下去 解释这章附带的一个简单的 web 服务器 超文本传输协议 HTTP HTTP 是一种协议 允许 web 服务器和浏览器通过互联网进行来发送和接受数据 它是一种请求 和响应协议 客户端请求一个文件而服务器响应请求 HTTP 使用可靠的 TCP 连接 TCP 默认使用 80 端口 第一个 HTTP 版是 HTTP 0 9 然后被 HTTP 1 0 所替代 正在取代 HTTP 1 0 的是当 前版本 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 浏览器的时候 可以通过点击浏览器上的停止按钮来停止一个文 件的下载进程 从而有效 的关闭与 web 服务器的 HTTP 连接 HTTP 请求 一个 HTTP 请求包括三个组成部分 方法 统一资源标识符 URI 协议 版本 请求的头部 主体内容 下面是一个 HTTP 请求的例子 POST examples default jsp HTTP 1 1 Accept text plain text html Accept Language en gb Connection Keep Alive Host localhost User Agent Mozilla 4 0 compatible MSIE 4 01 Windows 98 Content Length 33 Content Type application x www form urlencoded Accept Encoding gzip deflate lastName Franks 一旦你成功创建了一个 Socket 类的实例 你可以使用它来发送和接受字节流 要发送字节流 你首先必须调用 Socket 类的 getOutputStream 方法来获取一个 java io OutputStream 对象 要发 送文本到一个远程应用 你经常要从返回的 OutputStream 对象中构造一个 java io PrintWriter 对象 要从连接的另一端接受字节流 你可以调用 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 out new PrintWriter socket getOutputStream autoflush BufferedReader in new BufferedReader new InputStreamReader socket getInputstream send an HTTP request to the web server out println GET index jsp HTTP 1 1 out println Host localhost 8080 out println Connection Close out println read the response boolean 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 console System out println sb toString socket close 请注意 为了从 web 服务器获取适当的响应 你需要发送一个遵守 HTTP 协议的 HTTP 请求 假 如你已经阅读了前面一节超文本传输协议 HTTP 你应 该能够理解上面代码提到的 HTTP 请求 注意 你可以本书附带的 com brainysoftware pyrmont util HttpSniffer 类来发送一个 HTTP 请求并显示响应 要使用这个 Java 程 序 你必须连接到互联网上 虽然它有可能并不会起作用 假如你有设置防火墙的话 ServerSocket 类 Socket 类代表一个客户端套接字 即任何时候你想连接到一个远程服务器应用的时候你构造的 套接字 现在 假如你想实施一个服务器应用 例如一个 HTTP 服务器或者 FTP 服务器 你需要一 种不同的做法 这是因为你的服务器必须随时待命 因为它不知道一个客户端应用什么时候会尝试 去连接它 为了让你 的应用能随时待命 你需要使用 ServerSocket 类 这是服务器套接 字的实现 ServerSocket 和 Socket 不同 服务器套接字的角色是等待来自客户端的连接请求 一旦服务 器套接字获得一个连接请求 它创建一个 Socket 实例来与客户端进行通信 要创建一个服务器套接字 你需要使用 ServerSocket 类提供的四个构造方法中的一个 你需要 指定 IP 地址和服务器套接字将要进行监听的端口号 通 常 IP 地址将会是 127 0 0 1 也就是说 服务器套接字将会监听本地机器 服务器套接字正在监听的 IP 地址被称为是绑定地址 服务器套接 字的另一 个重要的属性是 backlog 这是服务器套接字开始拒绝传入的请求之前 传入的连接请求 的最大队列长度 其中一个 ServerSocket 类的构造方法如下所示 public ServerSocket int port int backLog InetAddress bindingAddress 对于这个构造方法 绑定地址必须是 InetAddress 的一个实例 一种构造 InetAddress 对象的简单的方法是调用它的静态 方法 getByName 传入一个包含主机名称的字符串 就像下面的代码一样 InetAddress getByName 127 0 0 1 下面一行代码构造了一个监听的本地机器 8080 端口的 ServerSocket 它的 backlog 为 1 new ServerSocket 8080 1 InetAddress getByName 127 0 0 1 一旦你有一个 ServerSocket 实例 你可以让它在绑定地址和服务器套接字正在监听的端口上等 待传入的连接请求 你可以通过调用 ServerSocket 类的 accept 方法做到这点 这个方法只会在有 连接请求时才会返回 并且返回值是一个 Socket 类的实例 Socket 对象 接下去可以发送字节流并 从客户端应用中接受字节流 就像前一节 Socket 类 解释的那样 实际上 这章附带的程序中 accept 方法是唯一用到的方 法 应用程序 我们的 web 服务器应用程序放在 ex01 pyrmont 包里边 由三个类组成 HttpServer Request Response 这个应用程序的入口点 静态 main 方法 可以在 HttpServer 类里边找到 main 方法创建了一个 HttpServer 的实例并调用了它的 await 方法 await 方法 顾名思义就是在一个指定的端口上等待 HTTP 请求 处理它们并发送响应返回客户端 它一直等待直至接收到 shutdown 命令 应用程序不能做什么 除了发送静态资源 例如放在一个特定目录的 HTML 文件和图像文件 它 也在控制台上显示传入的 HTTP 请求的字节流 不过 它不给浏 览器发送任何的头部例如日期或者 cookies 现在我们将在以下各小节中看看这三个类 HttpServer 类 HttpServer 类代表一个 web 服务器并展示在 Listing 1 1 中 请注意 await 方法放在 Listing 1 2 中 为了节省空间没有重复放在 Listing 1 1 中 Listing 1 1 HttpServer 类 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 ROOT 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 command private static final String SHUTDOWN COMMAND SHUTDOWN the shutdown command received private 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 int 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 request while shutdown Socket socket null InputStream input null OutputStream output null try socket serverSocket accept input socket getInputStream output socket getOutputStream create Request object and parse Request request new Request input request parse create Response object Response response new Response output response setRequest request response sendStaticResource Close the socket socket close check if the previous URI is a shutdown command shutdown 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 dir File separator webroot 代码列表包括一个叫 webroot 的目录 包含了一些你可以用来测试这个应用程序的静态资源 你同样可以在相同的目录下找到几个 servlet 用于测试下 一章的应用程序 为了请求一个静态资源 在你的浏览器的地址栏或者网址框里边敲入以下的 URL http machineName port staticResource 如果你要从一个不同的机器上发送请求到你的应用程序正在运行的机器上 machineName 应该 是正在运行应用程序的机器的名称或者 IP 地址 假如你的 浏览器在同一台机器上 你可以使用 localhost 作为 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 类的一个重 要方法 await 方法首先创建一个 ServerSocket 实例然后进入一个 while 循环 serverSocket new ServerSocket port 1 InetAddress getByName 127 0 0 1 Loop waiting for a request while shutdown while 循环里边的代码运行到 ServletSocket 的 accept 方法停了下来 只会在 8080 端口接收 到一个 HTTP 请求的时候才返回 socket serverSocket accept 接收到请求之后 await 方法从 accept 方法返回的 Socket 实例中取得 java io InputStream 和 java io OutputStream 对象 input socket getInputStream output socket getOutputStream await 方法接下去创建一个 ex01 pyrmont Request 对象并且调用它的 parse 方法去解析 HTTP 请求的原始数据 create Request object and parse Request request new Request input request parse 在这之后 await 方法创建一个 Response 对象 把 Request 对象设置给它 并调用它的 sendStaticResource 方法 create Response object Response response new Response output response setRequest request response sendStaticResource 最后 await 关闭套接字并调用 Request 的 getUri 来检测 HTTP 请求的 URI 是不是一个 shutdown 命令 假如是的 话 shutdown 变量将被设置为 true 且程序会退出 while 循环 Close the socket socket close check if the previous URI is a shutdown command shutdown request getUri equals SHUTDOWN COMMAND Request 类 ex01 pyrmont Request 类代表一个 HTTP 请求 从负责与客户端通信的 Socket 中传递过来 InputStream 对象来构造这个类 的一个实例 你调用 InputStream 对象其中一个 read 方法来获取 HTTP 请求的原始数据 Request 类显示在 Listing 1 3 Request 对象有 parse 和 getUri 两个公共方法 分别在 Listings 1 4 和 1 5 列出来 Listing 1 3 Request 类 package ex01 pyrmont import java io InputStream import java io IOException public class Request private InputStream input private String uri public Request InputStream input this input input public void parse private String parseUri String requestString public String getUri return uri Listing 1 4 Request 类的 parse 方法 public void parse Read a set of characters from the socket StringBuffer request new StringBuffer 2048 int i byte buffer new byte 2048 try i input read buffer catch IOException e e printStackTrace i 1 for int j 0 j index1 return requestString substring index1 1 index2 return null parse 方法解析 HTTP 请求里边的原始数据 这个方法没有做很多事情 它唯一可用的信息是通 过调用 HTTP 请求的私有方法 parseUri 获得的 URI parseUri 方法在 uri 变量里边存储 URI 公共 方法 getUri 被调用并返回 HTTP 请求的 URI 注意 在第 3 章和下面各章的附带程序里边 HTTP 请求将会对原始数据进行更多的处理 为了理解 parse 和 parseUri 方法是怎样工作的 你需要知道上一节 超文本传输协议 HTTP 讨论的 HTTP 请求的结构 在这一章中 我们仅 仅关注 HTTP 请求的第一部分 请求行 请求行从一 个方法标记开始 接下去是请求的 URI 和协议版本 最后是用回车换行符 CRLF 结束 请求行里边 的 元素是通过一个空格来分隔的 例如 使用 GET 方法来请求 index html 文件的请求行如下所示 GET index html HTTP 1 1 parse 方法从传递给 Requst 对象的套接字的 InputStream 中读取整个字节流并在一个缓冲区中 存储字节数组 然后它使用缓冲区字节数据的字 节来填入一个 StringBuffer 对象 并且把代表 StringBuffer 的字符串传递给 parseUri 方法 parse 方法列在 Listing 1 4 然后 parseUri 方法从请求行里边获得 URI Listing 1 5 给出了 parseUri 方法 parseUri 方 法搜索请求里边的第一个和第二个空格并从中获取 URI Response 类 ex01 pyrmont Response 类代表一个 HTTP 响应 在 Listing 1 6 里边给出 Listing 1 6 Response 类 package ex01 pyrmont import java io OutputStream import java io IOException import java io FileInputStream import java io File HTTP Response Status Line general header response header entity header CRLF CRLF message body Status Line HTTP Version SP Status Code SP Reason Phrase CRLF public class Response private static final int BUFFER SIZE 1024 Request request OutputStream output public Response OutputStream output this output output public void setRequest Request request this request request public void sendStaticResource throws IOException byte bytes new byte BUFFER SIZE FileInputStream fis null try File file new File HttpServer WEB ROOT request getUri if file exists fis new FileInputStream file int ch fis read bytes 0 BUFFER SIZE while ch 1 output write bytes 0 ch ch fis read bytes 0 BUFFER SIZE else file not found String errorMessage HTTP 1 1 404 File Not Found r n Content Type text html r n Content Length 23 r n r n File Not Found output write errorMessage getBytes catch Exception e thrown if cannot instantiate a File object System out println e toString finally if fis null fis close 首先注意到它的构造方法接收一个 java io OutputStream 对象 就像如下所示 public Response OutputStream output this output output 响应对象是通过传递由套接字获得的 OutputStream 对象给 HttpServer 类的 await 方法来构造 的 Response 类有两个公共方 法 setRequest 和 sendStaticResource setRequest 方法用来传递 一个 Request 对象给 Response 对象 sendStaticResource 方法是用来发送一个静态资源 例如一个 HTML 文件 它首先通过传递上 一级目录的路径和子路径给 File 累的构造方 法来实例化 java io File 类 File file new File HttpServer WEB ROOT request getUri 然后它检查该文件是否存在 假如存在的话 通过传递 File 对象让 sendStaticResource 构造 一个 java io FileInputStream 对象 然后 它调用 FileInputStream 的 read 方法并把字节数组 写入 OutputStream 对象 请注意 这种情况下 静态资源是作为原始数据发送给浏览器的 if file exists fis new FileInputstream file int ch fis read bytes 0 BUFFER SIZE while ch 1 output write bytes 0 ch ch fis read bytes 0 BUFFER SIZE 假如文件并不存在 sendStaticResource 方法发送一个错误信息到浏览器 String errorMessage Content Type text html r n Content Length 23 r n r n File Not Found output write errorMessage getBytes 运行应用程序 为了运行应用程序 可以在工作目录下敲入下面的命令 java ex01 pyrmont HttpServer 为了测试应用程序 可以打开你的浏览器并在地址栏或网址框中敲入下面的命令 http localhost 8080 index html 正如 Figure 1 1 所示 你将会在你的浏览器里边看到 index html 页面 Figure 1 1 web 服务器的输出 在控制台中 你可以看到类似于下面的 HTTP 请求 GET index html HTTP 1 1 Accept image gif image x xbitmap image jpeg image pjpeg application vnd ms excel application msword application vnd ms powerpoint application x shockwave flash application pdf Accept Language en us Accept Encoding gzip deflate User Agent Mozilla 4 0 compatible MSIE 6 0 Windows NT 5 1 NET CLR 1 1 4322 Host localhost 8080 Connection Keep Alive GET images logo gif HTTP 1 1 Accept Referer http localhost 8080 index html Accept Language en us Accept Encoding gzip deflate User Agent Mozilla 4 0 compatible MSIE 6 0 Windows NT 5 1 NET CLR 1 1 4322 Host localhost 8080 Connection Keep Alive 总结 在这章中你已经看到一个简单的 web 服务器是如何工作的 这章附带的程序仅仅由三个类组成 并不是全功能的 不过 它提供了一个良好的学习工具 下一章将 要讨论动态内容的处理过程 第 2 章 一个简单的 Servlet 容器 概要 本章通过两个程序来说明你如何开发自己的 servlet 容器 第一个程序被设计得足够简单使得 你能理解一个 servlet 容器是如何工作的 然后它演变为 第二个稍微复杂的 servlet 容器 注意 每一个 servlet 容器的应用程序都是从前一章的应用程序逐渐演变过来的 直至一个全 功能的 Tomcat servlet 容器在第 17 章被建立起来 这两个 servlet 容器都可以处理简单的 servlet 和静态资源 你可以使用 PrimitiveServlet 来 测试这个容器 PrimitiveServlet 在 Listing 2 1 中列出并且它的类文件可以在 webroot 目录下 找到 更复杂的 servlet 就超过这些容器的能力了 但是你将会在以下各章中学到如何建立更复杂 的 servlet 容器 Listing 2 1 PrimitiveServlet java import javax servlet import java io IOException import java io PrintWriter public class PrimitiveServlet implements Servlet public void init ServletConfig config throws ServletException System out println init public void service ServletRequest request ServletResponse response throws ServletException IOException System out println from service PrintWriter out response getWriter out println Hello Roses are red out print Violets are blue public void destroy System out println destroy public String getServletInfo return null public ServletConfig getServletConfig return null 两个应用程序的类都放在 ex02 pyrmont 包里边 为了理解应用程序是如何工作的 你需要熟悉 javax servlet Servlet 接口 为 了给你复习一下 将会在本章的首节讨论这个接口 在这之后 你将会学习一个 servlet 容器做了什么工作来为一个 servlet 提供 HTTP 请求 javax servlet Servlet 接口 Servlet 编程是通过 javax servlet 和 javax servlet http 这两个包的类和接口来实现的 其 中一个至关重要的就是 javax servlet Servlet 接口了 所有的 servlet 必须实现实现或者继承实 现该接口的类 Servlet 接口有五个方法 其用法如下 public void init ServletConfig config throws ServletException public void service ServletRequest request ServletResponse response throws ServletException java io IOException public void destroy public ServletConfig getServletConfig public java lang String getServletInfo 在 Servlet 的五个方法中 init service 和 destroy 是 servlet 的生命周期方法 在 servlet 类已经初始化之后 init 方法将会被 servlet 容器所调用 servlet 容器只调用一次 以此表明 servlet 已经被加载进服务中 init 方法必须在 servlet 可以 接受任何请求之前成功运行完毕 一 个 servlet 程序员可以通过覆盖这个方法来写那些仅仅只要运行一次的初始化代码 例如加载数据 库驱动 值初始化等 等 在其他情况下 这个方法通常是留空的 servlet 容器为 servlet 请求调用它的 service 方法 servlet 容器传递一个 javax servlet ServletRequest 对象和 javax servlet ServletResponse 对象 ServletRequest 对象包括客户端的 HTTP 请求信息 而 ServletResponse 对象封装 servlet 的响应 在 servlet 的生 命周期中 service 方法将会给调用多次 当从服务中移除一个 servlet 实例的时候 servlet 容器调用 destroy 方法 这通常发生在 servlet 容器正在被关闭或者 servlet 容器需要一些空闲内存的时候 仅仅在所有 servlet 线程的 service 方法已经退出或者超时淘汰的时候 这个方法才被调用 在 servlet 容器已 经调用完 destroy 方法之后 在同一个 servlet 里边将不会再调用 service 方法 destroy 方法提供了一个机 会来清理任何已经被占用的 资源 例如内存 文件句柄和线程 并确保任何持久化状态和 servlet 的内存当前状态是同步的 Listing 2 1 介绍了一个名为 PrimitiveServlet 的 servlet 的代码 是一个非常简单的的 servlet 你可以用来测试本章里边的 servlet 容器应用程序 PrimitiveServlet 类实现了 javax servlet Servlet 所有的 servlet 都必须这样 做 并为 Servlet 的这五个方法都提供了实 现 PrimitiveServlet 做的事情非常简单 在 init service 或者 destroy 中的任何一个方法每次 被调用的时候 servlet 把方法名写到标准控制台上面去 另外 service 方法从 ServletResponse 对象获得 java io PrintWriter 实例 并发送字符串到浏览器去 应用程序 1 现在 让我们从
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 解决方案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!