- 浏览: 102510 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
daichenqiu:
写的很好啊,赞!
Tomcat :一个简单的Servlet容器 -
Jnerd:
Handler初始化的应该注册read,否则select就会阻 ...
NIO Reactor模式(阅读NIO笔记) -
Jnerd:
运行了不正确呢
NIO Reactor模式(阅读NIO笔记)
Tomcat4默认连接器
tomcat连接器是一个独立的模块,可以插入到一个servlet容器。一个tomcat连接器必须符合以下要求:
- 必须实现org.apache.catalina.Connector接口
- 必须创建一个实现org.apache.catalina.Request接口的request对象
- 必须创建一个实现org.apache.catalina.Response接口的response对象
Container接口的invoke方法:
/** * Process the specified Request, and generate the corresponding Response, * according to the design of this particular Container. * * @param request Request to be processed * @param response Response to be produced * * @exception IOException if an input/output error occurred while * processing * @exception ServletException if a ServletException was thrown * while processing this request */ public void invoke(Request request, Response response) throws IOException, ServletException;
在invoke方法中,容器加载servlet类、调用service方法、管理session、记录错误信息日志等等。
使用对象池来降低复杂对象的创建开销。
*HTTP1.1新特性
- 持久连接
在HTTP1.0中,每对Request/Response都使用一个新的连接。
HTTP 1.1则支持Persistent Connection, 并且默认使用persistent connection.
connection: keep-alive
- 块编码
HTTP1.1支持chunked transfer,所以可以有Transfer-Encoding头部域,HTTP1.0则没有。
Transfer-Encoding: chunked
1D\r\n I'm as helpless as a kitten u 9\r\n p a tree. 0\r\n
- 状态100的使用
100 (Continue) 状态代码的使用,允许客户端在发request消息body之前先用request header试探一下server,看server要不要接收request body,再决定要不要发request body。
客户端在Request头部中包含Expect: 100-continue
Server看到之后呢如果回100 (Continue) 这个状态代码,客户端就继续发request body。
HTTP/1.1 100 Continue
HttpConnector类
(1)如何创建一个server socket?
(2)如何维护HttpProcessor池?
(3)如何处理Http请求?
org.apache.catalina.connetor.http.HttpConnector类,实现了org.apache.catalina.Connector、java.lang.Runnable和org.apache.catalina.LifeCycle接口。LifeCycle接口用来维护每一个实现了此接口的Catalina组件的生命周期。
- 创建一个server socket
- private ServerSocket open() throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException,
- UnrecoverableKeyException, KeyManagementException {
- // Acquire the server socket factory for this Connector
- ServerSocketFactory factory = getFactory();
- // If no address is specified, open a connection on all addresses
- if (address == null) {
- log(sm.getString("httpConnector.allAddresses"));
- try {
- return (factory.createSocket(port, acceptCount));
- } catch (BindException be) {
- throw new BindException(be.getMessage() + ":" + port);
- }
- }
- // Open a server socket on the specified address
- try {
- InetAddress is = InetAddress.getByName(address);
- log(sm.getString("httpConnector.anAddress", address));
- try {
- return (factory.createSocket(port, acceptCount, is));
- } catch (BindException be) {
- throw new BindException(be.getMessage() + ":" + address + ":" + port);
- }
- } catch (Exception e) {
- log(sm.getString("httpConnector.noAddress", address));
- try {
- return (factory.createSocket(port, acceptCount));
- } catch (BindException be) {
- throw new BindException(be.getMessage() + ":" + port);
- }
- }
- }
- 如何维护HttpProcessor池
首先采用栈来存储HttpProcessor实例,HttpProcessor池动态扩容,根据三个属性来设置:
curProcessors: 当前HttpProcessor实例的个数
minProcessors : int 初始化时,最小的HttpProcessor实例个数
maxProcessors:最大HttpProcessor实例个数,当小于0时,不做限制
初始化时创建最小HttpProcessor实例个数代码:
- // Create the specified minimum number of processors
- while (curProcessors < minProcessors) {
- if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
- break;
- HttpProcessor processor = newProcessor();
- recycle(processor);
- }
- 处理http请求
HttpConnector类在自己的run方法中有自己的主要逻辑,直到HttpConnetor停止之前都会一直等待接收http请求。对于每一个http请求,通过调用createProcessor方法获得一个HttpProcessor实例。然而,大多数时间,createProcessor方法并不会创建一个新的HttpProcessor对象,而是从一个HttpProcessor池中获取。如果在这个池中(实际采用的是堆栈来存储)有一个HttpProcessor实例可供使用,执行出栈操作。如果栈为空且仍然没有超过HttpProcessor实例的最大个数,则创建一个新的HttpProcessor实例,否则,createProcessor方法将返回null,此时socket执行关闭操作而不会响应到来的http请求。如果createProcessor方法没有返回null,客户端的socket传递给HttpProcessor的assign方法。
- private HttpProcessor createProcessor() {
- synchronized (processors) {
- if (processors.size() > 0) {
- return ((HttpProcessor) processors.pop());
- }
- if ((maxProcessors > 0) && (curProcessors < maxProcessors)) {
- return (newProcessor());
- } else {
- if (maxProcessors < 0) {
- return (newProcessor());
- } else {
- return (null);
- }
- }
- }
- }
HttpProcessor类
在本章,我们最感兴趣的是HttpProcessor类如何使assign方法异步以便HttpConnetor实例可以同时为多个http请求服务。HttpProcessor类中另外一个重要的方法是私有方法process方法,它解析了http请求并且调用了容器的invoke方法。
第三章中,HttpConnetor在自己的线程中运行,然而它必须等待当前处理的http请求结束之后才可以处理下一个请求。
第三章的HttpConnetor类的run方法代码如下:
public void run() { 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); } while (!stopped) { // Accept the next incoming connection from the server socket Socket socket = null; try { socket = serverSocket.accept(); } catch (Exception e) { continue; } // Hand this socket off to an HttpProcessor HttpProcessor processor = new HttpProcessor(this); processor.process(socket); } }
HttpProcessor类的process方法在第三章中是同步方法。因此,它的run方法等待直到process方法处理结束才接收下一个请求。在本章,默认的连接器的HttpProcessor类实现了Runnable接口,因此每一个HttpProcessor实例都运行在自己的线程中,我们称为“processor线程”
Lifecycle接口的start和stop方法
/** * Prepare for the beginning of active use of the public methods of this * component. This method should be called before any of the public * methods of this component are utilized. It should also send a * LifecycleEvent of type START_EVENT to any registered listeners. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ public void start() throws LifecycleException; /** * Gracefully terminate the active use of the public methods of this * component. This method should be the last one called on a given * instance of this component. It should also send a LifecycleEvent * of type STOP_EVENT to any registered listeners. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ public void stop() throws LifecycleException;
HttpProcessor实现了Lifecycle接口,因此HttpProcessor类的start方法代码如下:
/** * 判断HttpProcessor组件是否启动 */ private boolean started = false;
/** * Start the background thread we will use for request processing. * * @exception LifecycleException if a fatal startup error occurs */ public void start() throws LifecycleException { if (started) throw new LifecycleException (sm.getString("httpProcessor.alreadyStarted")); lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; threadStart(); }
/** * 开启后台处理线程 */ private void threadStart() { log(sm.getString("httpProcessor.starting")); thread = new Thread(this, threadName); thread.setDaemon(true); thread.start(); if (debug >= 1) log(" Background thread has been started"); }
HttpProcessor的run方法的while循环执行流程:获得一个socket,处理它,调用connector的recycle(回收)方法把当前的HttpProcessor实例压回栈中。注意到while循环中停止到await方法处,await方法掌握着“processor thread”的控制流,直到它从HttpConnetor获得到一个新的socket对象。换句话说,直到HttpConnetor类调用HttpProcessor实例的assign方法。
HttpProcessor processor = createProcessor(); processor.assign(socket);
HttpProcessor的run方法代码如下:
/* * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ public void run() { // Process requests until we receive a shutdown signal while (!stopped) { // Wait for the next socket to be assigned Socket socket = await(); if (socket == null) continue; // Process the request from this socket try { process(socket); } catch (Throwable t) { log("process.invoke", t); } // Finish up this request connector.recycle(this); } // Tell threadStop() we have shut ourselves down successfully synchronized (threadSync) { threadSync.notifyAll(); } }
将调用完的HttpProcessor实例压回栈中的代码实现:
void recycle(HttpProcessor processor) { processors.push(processor); }
然而,await方法和assign方法运行在不同的线程中,assign方法是在HttpConnetor的run方法中被调用的,即“connector线程”。
那么assign方法是如何告诉await方法它被调用了呢?
利用一个布尔型变量available和java.lang.Object类的wait和notifyAll方法。
注:Object的wait方法导致当前线程等待直到其他线程对这个对象调用notify或者nitifyAll方法。
connetor线程调用的assign方法:
/** * Process an incoming TCP/IP connection on the specified socket. Any * exception that occurs during processing must be logged and swallowed. * <b>NOTE</b>: This method is called from our Connector's thread. We * must assign it to our own thread so that multiple simultaneous * requests can be handled. * * @param socket TCP socket to process */ synchronized void assign(Socket socket) { // Wait for the Processor to get the previous Socket while (available) { try { wait(); } catch (InterruptedException e) { } } // Store the newly available Socket and notify our thread this.socket = socket; available = true; notifyAll(); if ((debug >= 1) && (socket != null)) log(" An incoming request is being assigned"); }
HttpProcessor线程调用的await方法:
/** * Await a newly assigned Socket from our Connector, or <code>null</code> * if we are supposed to shut down. */ private synchronized Socket await() { // Wait for the Connector to provide a new Socket while (!available) { try { wait(); } catch (InterruptedException e) { } } // Notify the Connector that we have received this Socket Socket socket = this.socket; available = false; notifyAll(); if ((debug >= 1) && (socket != null)) log(" The incoming request has been awaited"); return (socket); }
初始时,当“processor thread”刚启动时,available为false,即还没有可用的socket。因此线程在while循环中等待,直到其他线程调用notify或者notifyAll方法。也就是说,调用wait方法导致“processor thread”暂停直到“connector thread”对这个HttpProcessor实例调用notifyAll方法。当一个新的socket被分配,“connector thread”调用HttpProcessor的assign方法。avilable置为true,唤醒“processor thread”。
为什么await方法需要使用一个本地变量(socket)且不返回这个socket变量的实例?
因为HttpProcessor实例的socket变量在当前socket处理完之前还可以分配给下一个到来的socket。
为什么await方法需要调用notifyAll?
为了当另外一个socket到达的时候此时available为true,这时候,“connector thread”将会停止里面的assign方法直到收到“processor thread”的notifyAll方法。
发表评论
-
web.xml配置
2012-11-08 18:22 10741.< context-param> conte ... -
Tomcat与web开发技术详解读书笔记(2)过滤器(7)
2011-11-26 14:05 0补充:Servlet监听器 类似与Swing界 ... -
Tomcat与web开发技术详解读书笔记(2)过滤器(6)
2011-11-26 14:03 0web开发中常用的字符集编码过滤器 < ... -
Tomcat与web开发技术详解读书笔记(2)过滤器(4)
2011-11-26 14:02 0public class LoginFilter imp ... -
Tomcat与web开发技术详解读书笔记(2)过滤器(3)
2011-11-26 14:01 0doFilter(ServletRequest req, ... -
Tomcat与web开发技术详解读书笔记(2)过滤器(2)
2011-11-26 13:59 0init(FilterConfig config):过滤 ... -
Tomcat与web开发技术详解读书笔记(2)过滤器
2012-09-18 17:31 26401.简介 过滤器能够在Servlet、JSP或HTML等w ... -
mybatis入门
2011-11-21 20:13 01.什么是MyBatis MyBatis是支持普通SQ ... -
How tomcat works 第四章学习笔记(6)
2011-11-20 21:40 0利用一个布尔型变量available和java.lang.Ob ... -
How tomcat works 第四章学习笔记(5)
2011-11-20 21:19 0HttpProcessor实现了Lifecycle接口,因此H ... -
How tomcat works 第四章学习笔记(4)
2011-11-20 20:42 0HttpProcessor类 在本章,我们最感兴趣的是 ... -
How tomcat works 第四章学习笔记(2)
2011-11-20 20:01 51. HttpConnector类 (1)如何创建一个ser ... -
Tomcat与web开发技术详解读书笔记(2)
2011-11-20 17:01 51. 浏览器端与用户的动态交互 脚本语言:web服务器直接把 ... -
Tomcat与web开发技术详解读书笔记(1)Http协议简介
2011-11-20 16:54 9671.HTTP协议简介 超文本传输协议,是关于如何 ... -
How tomcat works 第四章学习笔记(3)
2011-11-16 20:10 9HttpConnector类 如何维护HttpProces ... -
Servlet监听器
2011-09-04 18:03 7130Servlet监听器用于监听一些重要事件的发生,监听器对象可以 ... -
工作相关的术语
2011-09-04 01:27 10731.SOA (Service-Oriented Archite ... -
MySql慢查询日志
2011-09-04 00:26 1151转自:http://www.cnblogs.com/wenan ... -
Quartz—调度框架
2011-09-02 23:45 0Quartz Scheduler 2.0 对以前的API ... -
【转】svn文件清除批处理工具
2011-03-24 00:27 2012来源:http://darkmasky.iteye.com/b ...
相关推荐
通过阅读《How Tomcat Works》中文版,读者将能够获得对Tomcat架构的全面理解,学习到如何从源码级别研究和开发一个高性能的Java应用服务器,以及如何将其应用于实际的Web开发和服务器管理工作中。
《How Tomcat Works》是一份深入探讨Apache Tomcat工作原理的重要资源,包含了英文PDF文档、中文HTML翻译以及源代码,旨在帮助读者理解Tomcat服务器的内部运作机制。这份资料是IT从业者,特别是Java Web开发者、系统...
总的来说,《How Tomcat Works》中文版结合源码学习,可以帮助读者全面掌握Tomcat的工作原理,提升对Web应用服务器的理解,并且能更好地进行问题排查和性能优化。书中的例程源码可以作为实践参考,加深理论知识与...
第四章则关注Tomcat的并发模型。Tomcat支持两种并发模型:基于线程的模型和基于NIO(非阻塞I/O)的模型。基于线程的模型中,每个请求都会分配一个线程,而NIO模型使用较少的线程来处理更多的连接,降低了线程创建和...
《译How Tomcat Works(第二章)》这篇文章主要讲解了Apache Tomcat服务器的工作原理,它是一个开源的Java Servlet容器,广泛用于部署Web应用程序。在这一章中,我们将深入探讨Tomcat如何处理HTTP请求,以及其内部架构...
《How Tomcat Works》是一本深入解析Apache Tomcat工作原理的书籍,同时也包含了源码,为读者提供了理论与实践相结合的深入学习体验。Tomcat是一款广泛使用的开源Java Servlet容器,它是Apache软件基金会 Jakarta...
《How Tomcat Works》这本书是理解Apache Tomcat服务器工作原理的宝贵资源,它全面深入地讲解了这个流行的Java Servlet和JavaServer Pages(JSP)容器的内部机制。书中的20个章节涵盖了从基础概念到高级特性的广泛...
在《How Tomcat Works》一书中,作者不仅仅是提供一个简单的Tomcat学习蓝图,而是通过构建简化版本的组件来帮助读者逐步深入理解真实组件的工作机制,让读者能够更容易地掌握整个Tomcat的运作原理。
### How Tomcat Works中文版深度解析 #### 一、引言与概述 《How Tomcat Works》是一本针对Apache Tomcat服务器内部工作机制进行深入剖析的专业书籍。本书详细介绍了Tomcat 4.1.12和5.0.18两个版本的内部结构与...
《How Tomcat Works》这本书深入浅出地介绍了Apache Tomcat这款广泛应用的Java Servlet容器的工作原理。Tomcat作为开源软件,是许多Web应用的基础,尤其在轻量级开发和测试环境中非常常见。以下是对Tomcat核心知识点...
《How Tomcat Works》这本书是理解Apache Tomcat服务器工作原理的重要资源,第三章主要探讨了Tomcat的架构和核心组件。以下是对这部分内容的详细解读: Tomcat作为一款开源的Java Servlet容器,其核心功能是解析...
HowTomcatWorks书籍课程实例工程与代码 书籍剖析了Tomcat 4.1.12和Tomcat 5.0.18--一个免费的、开源的、深受大众欢迎的、代号为Catalina的servlet容器,并讲解其容器的内部运行机制。通过迭代实现一个简化版软件来...
《HowTomcatWorks》是一本深入解析Apache Tomcat工作原理的书籍,中文版的发布使得更多的中国开发者能够理解和掌握这款广泛应用的开源Java Servlet容器的工作机制。Tomcat是Apache软件基金会Jakarta项目的一部分,它...
《How Tomcat Works》是一本深入探讨Apache Tomcat工作原理的书籍,包含了中英文两个版本。这本书对于理解Java Servlet和JavaServer Pages(JSP)容器的运作方式具有极高的价值,特别是对于那些想要深入理解Web应用...
tomcat工作原理深入详解——HowTomcatWorks中文版.pdf
《How Tomcat Works》是一本深入解析Apache Tomcat服务器内部工作原理的重要参考资料,它提供了对Tomcat架构的全面理解,包括其设计、配置和优化。这本书的中文版和英文版都为读者提供了便利,无论你是母语为中文...