书接上文。
当Tomcat的Acceptor监听到有请求到来时,就会结束阻塞,继续进行程序下面的动作。如下面的代码所示:
public void run() { while (running) { while (paused) { try { Thread.sleep(1000); } catch (InterruptedException e) { } } try { // 开始监听端口 Socket socket = serverSocketFactory.acceptSocket(serverSocket); // 初始化Socket serverSocketFactory.initSocket(socket); // 处理Socket if (!processSocket(socket)) { try { socket.close(); } catch (IOException e) { } } } catch (IOException x) { if (running) log.error(sm.getString("endpoint.accept.fail"), x); } catch (Throwable t) { log.error(sm.getString("endpoint.accept.fail"), t); } } }
结束阻塞后,首先是Socket的初始化,由于ServerSocketFactory的实现类DefaultServerSocketFactory并没有扩展initSocket()方法,所以这一步其实是什么都没做的。
接下来程序执行到了processSocket(socket);这一步了,这个方法的源代码如下所示:
protected boolean processSocket(Socket socket) { try { if (executor == null) { // 得到一个Work并为它分配这个Socket getWorkerThread().assign(socket); } else { executor.execute(new SocketProcessor(socket)); } } catch (Throwable t) { log.error(sm.getString("endpoint.process.fail"), t); return false; } return true; }
executor是一个外部的基于线程池的执行器,先不去考虑它,重点看一下getWorkerThread()和Worker#assign()
getWorkerThread()的源代码如下:
protected Worker getWorkerThread() { // 获取一个Worker Worker workerThread = createWorkerThread(); while (workerThread == null) {// 如果获取的Worker为Null try { synchronized (workers) { // 等待workers里边Worker的回收,recycleWorkerThread()中会调用notify通知这个线程结束等待的 workers.wait(); } } catch (InterruptedException e) { } // 等待结束,再次获取一个Worker workerThread = createWorkerThread(); } return workerThread; }
这里这个createWorkerThread()也就是获取Worker的方法值得研究一下。
protected Worker createWorkerThread() { synchronized (workers) { if (workers.size() > 0) {// 如果堆栈中有剩余的Worker // 当前在使用的Worker线程计数 curThreadsBusy++; // 将一个Worker推出堆栈 return workers.pop(); } // 如果堆栈中没有多余的Worker了,那么创建一个。 if ((maxThreads > 0) && (curThreads < maxThreads)) { // 如果maxThreads有定义,并且当前的Worker数量小于这个值。 // 在recycleWorkerThread()中会将新创建的Worker放入堆栈的 curThreadsBusy++; return (newWorkerThread()); } else { if (maxThreads < 0) { // maxThreads没有定义,可以有无限个Worker的情况。 curThreadsBusy++; return (newWorkerThread()); } else { return (null); } } } }
而newWorkerThread()方法还是很好理解的:
protected Worker newWorkerThread() { Worker workerThread = new Worker(); workerThread.start(); return (workerThread); }
创建一个Worker线程,并且开启线程。
经过上述的过程,就获得了一个Worker(并且已经开始运行了),那么程序的下一步是调用Worker的assign()方法:
synchronized void assign(Socket socket) { // 等待获取完上一个Socket while (available) { try { wait(); } catch (InterruptedException e) { } } // 保存新的Socket this.socket = socket; available = true; notifyAll(); }
这样新的Worker已经有一个Socket对象去处理了,下面来看一下Worker的线程中做了哪些工作。
public void run() { // 知道收到停止信号,否则一直循环 while (running) { // 等待为这个线程设置一个Socket对象 Socket socket = await(); if (socket == null) continue; // 处理请求 if (!setSocketOptions(socket) || !handler.process(socket)) { // 关闭Socket try { socket.close(); } catch (IOException e) { } } // 回收Worker socket = null; recycleWorkerThread(this); } }
其中await()用于等待有Socket对象赋给当前的Worker已进行请求处理,代码如下:
private synchronized Socket await() { // 等待获取Socket while (!available) { try { wait(); } catch (InterruptedException e) { } } // Socket已经收到 Socket socket = this.socket; available = false; // 这个notifyAll()是通知assign()中的等待Socket的处理已经开始了, // 可以为这个Worker赋新的值了。 notifyAll(); return (socket); }
而setSocketOptions()用于设定一些Socket的参数,如下所示:
protected boolean setSocketOptions(Socket socket) { int step = 1; try { if (soLinger >= 0) { socket.setSoLinger(true, soLinger); } if (tcpNoDelay) { socket.setTcpNoDelay(tcpNoDelay); } if (soTimeout > 0) { socket.setSoTimeout(soTimeout); } step = 2; serverSocketFactory.handshake(socket); } catch (Throwable t) { if (log.isDebugEnabled()) { if (step == 2) { log.debug(sm.getString("endpoint.err.handshake"), t); } else { log.debug(sm.getString("endpoint.err.unexpected"), t); } } return false; } return true; }
handler.process(socket)封装了处理请求的全过程,下次再详细了解
而最后的recycleWorkerThread()用于回收Worker到堆栈中以备下次使用:
protected void recycleWorkerThread(Worker workerThread) { synchronized (workers) { workers.push(workerThread); curThreadsBusy--; workers.notify(); } }
好了,请求处理的整个流程大致就是这样的,下次再详细了解请求的真实处理部分,就是handler.process(socket)的内容。
发表评论
-
出现java.lang.UnsupportedClassVersionError 错误的原因
2010-08-16 23:11 871出现java.lang.UnsupportedClassVer ... -
Tomcat请求处理(七) - Servlet实例的调用
2009-05-07 11:36 1131Tomcat请求处理中Servlet实例的调用是和Filter ... -
请求在Tomcat中传到了CoyoteAdapter的#service()方法中后,就要准备进入Pi
2009-05-07 11:35 1810首先,来看一下Servlet的载入过程。 具体是在org.ap ... -
Tomcat请求处理(五) -- 请求在容器间的流动
2009-05-07 11:34 1433请求在Tomcat中传到了CoyoteAdapter的#ser ... -
Tomcat请求处理(四) -- Request, Response, 和Pipeline
2009-05-07 11:33 12831. Request和Response 当处理请求的时候,To ... -
Tomcat请求处理(三) -- coyote请求处理
2009-05-07 11:32 1323在上一篇文章文章中,Tomcat的请求处理到了JIoEndpo ... -
Tomcat请求处理(一) -- 服务器端口监听
2009-05-07 11:29 1400其实tomcat在哪个类中监听请求的代码很容易找到: 在org ... -
Tomcat启动部分源代码分析(五) -- 应用程序加载
2009-05-07 11:28 1199前面所叙述的tomcat启动 ... -
Tomcat启动部分源代码分析(四) -- 开启容器
2009-05-07 11:27 1204四. 开启容器 最后是Bootstrap#start()方法的 ... -
Tomcat启动部分源代码分析(三) -- 载入
2009-05-07 11:23 1194二. 载入 2. Bootstrap的#Bootstrap#l ... -
Tomcat启动部分源代码分析(二) -- 初始化
2009-05-07 11:20 1097二. 初始化 1. 首先是Bootstrap的#init()操 ... -
Tomcat启动部分源代码分析(一) -- 概览
2009-05-07 11:17 1432一. 概览 本文所涉及的Tomcat为6.0版本。 Tomca ... -
Tomcat的Session管理(二) - Session后台处理
2009-05-07 10:10 971Tomcat会开启一个后台线程每隔一段时间检查Session的 ... -
Tomcat的Session管理(一) - Session的生成
2009-05-07 10:02 1497Session对象的创建一般是源于这样的一条语句: Sessi ...
相关推荐
- **Connector**:处理HTTP请求和响应,是Tomcat与Web客户端通信的桥梁。 - ** Coyote**:Tomcat的HTTP/1.1连接器,负责监听和接受来自Web客户端的连接。 - **Juli**:Tomcat的日志框架,用于记录应用程序和...
通过分析源码,开发者可以学习到如何遵循Servlet和JSP规范进行服务器端开发,理解Tomcat如何处理请求、管理会话、调度线程等。此外,源码还便于开发者修复已知问题,优化性能,或添加特定的功能。 总之,`tomcat6-...
标题 "tomcat8-redis-session共享" 涉及到的是在Tomcat 8中使用Redis作为Session共享存储的解决方案。这是一个常见的需求,特别是在分布式系统中,为了保持用户会话的一致性,需要将Session数据在多台服务器之间共享...
- Catalina处理Servlet请求,Jasper编译并执行JSP,而Coyote负责与客户端进行网络通信。 2. **Tomcat 7.0.64版本特性**: - 改进了性能和稳定性,修复了多个安全漏洞。 - 支持Java EE 6 Web Profile,包括...
4. **Juli**:这是Tomcat的内置日志框架,可以自定义配置以满足不同日志需求。 5. **Cluster**:在集群环境中,Tomcat支持应用的分布式部署,能够实现会话复制和故障转移,提高可用性和可扩展性。 6. **Connector*...
本文将深入探讨Tomcat的工作原理,包括其启动流程、请求处理机制以及核心组件的功能。 1. **启动流程** - **初始化阶段**: Tomcat启动时会读取`server.xml`配置文件,该文件定义了服务器的各种配置,如端口号、...
- `work`:存放Tomcat处理请求时生成的临时文件和编译后的JSP文件。 安装和配置Apache Tomcat 7.0.63 的步骤包括: 1. 将解压后的目录放置在你选择的位置。 2. 配置环境变量,例如设置`CATALINA_HOME`指向Tomcat的...
8. **日志和错误处理**:查看和分析Tomcat的日志文件,理解常见的错误信息。 9. **性能优化**:内存调优、线程池配置、缓存策略等提高Tomcat性能的方法。 10. **集群和负载均衡**:如何设置Tomcat集群,实现多台...
4. **Juli**:Juli是Tomcat的内置日志框架,可以更灵活地管理和配置日志输出。 5. **Webapps**:在解压的文件中,你会找到一个名为"webapps"的目录,这里存放的是待部署的Web应用程序。你可以将WAR文件或已经展开的...
Tomcat默认使用JULI进行内部日志记录,包括服务器启动、关闭、请求处理等各种运行时信息。 最后,`tomcat-juli-adapters.jar`的作用在于桥接JULI和其他日志框架,例如Log4j。这个适配器允许Tomcat使用非JUL的日志...
4. **Juli**:Tomcat的日志框架。 5. **Cluster**(可选):如果需要集群部署,此组件支持Tomcat实例之间的通信和会话复制。 6. **Manager**:一个Web应用程序,可以用于管理部署在Tomcat服务器上的应用。 7. **Host...
Catalina是Servlet容器,负责处理Servlet请求;Apr提供高性能的网络连接;Coyote是HTTP/1.1协议处理器;而Jasper则用于解析和执行JSP文件。 2. **32位系统兼容**:由于这是针对32位Windows系统的版本,它将确保与...
这个"apache-tomcat-8.0.14-windows-x64"版本包含了运行和部署Java Web应用所需的所有组件,如Catalina(核心Servlet容器)、 Jasper(JSP编译器)、Juli(日志框架)和 Coyote(HTTP/1.1连接器)等。 在下载的...
9. **错误处理与日志系统**:Tomcat使用自定义的日志框架,源码中`logging`目录下的类定义了如何记录和处理错误信息。 10. **网络编程**:Tomcat底层使用NIO(非阻塞I/O)和BIO(阻塞I/O)模型,这在`java/org/...
Tomcat作为Servlet容器,它的主要任务是解析HTTP请求,并将这些请求传递给Java Servlets进行处理。Servlet是Java编程语言中用于动态创建Web内容的接口。Tomcat还支持JSP(JavaServer Pages),这是一种基于Java的...
Tomcat使用多线程模型处理并发请求,源码中可以看到Executor(执行器)和ThreadPool(线程池)的概念,它们有助于提高系统效率和资源利用率。 6. **安全与权限控制**: Tomcat支持多种安全机制,如SSL/TLS加密、 ...
64位版本的Tomcat可以处理更大内存需求的应用,这对于运行大型企业级应用或处理大量并发请求非常有用。 4. **安装与配置**: 解压"apache-tomcat-10.0.11-windows-x64.zip"后,用户需要配置环境变量,比如设置...
6. **Logging**: Tomcat提供了一套灵活的日志框架,可以根据需要配置日志输出,包括使用第三方日志库如Log4j。 7. **Web应用部署**: `conf/Catalina/localhost`目录下的XML文件定义了部署的Web应用,`webapps`目录...
Java Servlet是Java平台上的服务器端编程模型,用于处理HTTP请求并生成动态内容。JSP则是一种视图技术,允许开发者将HTML代码与Java代码混合,简化了网页开发。Tomcat作为Servlet和JSP容器,负责加载、执行并管理...
例如,Servlet是Java编程语言中用于处理HTTP请求的服务端组件,JSP则允许开发者用HTML或XML语法混合Java代码来创建动态网页。 在`apache-tomcat-7.0.108`目录下,你会找到以下几个关键部分: 1. `bin`目录:包含可...