设为首页 收藏本站
查看: 374|回复: 0

[经验分享] How Tomcat Works 读书笔记(第四章)

[复制链接]

尚未签到

发表于 2017-1-31 06:35:08 | 显示全部楼层 |阅读模式
How Tomcat Works 读书笔记(第四章)
2011年07月01日
       Tomcat的连接器是一个单独的模块,它可以插入到一个servlet容器里面,现在一些比较常见的连接器有Coyote,mod_jk, mod_jk2,和mod_webapp.一个Tomcat的连接器必须要满足下面的要求:  
  1. 它必须实现org.apache.catalina.Connector接口  
  2. 它必须要创建一个实现org.apache.catalina.Request对象的request  
  3. 它必须要创建一个实现org.apache.catalina.Response对象的response  
  Tomcat 4的连接器和第三章的差不多,它也是等待HTTP请求,创建reqeust和response对象,而后把request和response对象传给container容器。它是调用container的invoker方法来实现传递的:  
  Public void invoke (org.apache.catalina.Reqeust request, org.apache.catalina.Response response);  
  在invoke方法里面,container加载servlet类,调用它的service方法,管理session,并使用log等组件。这个connector对第三章的connector做了一些优化,第一点就是提供了一个池,避免了对象创建的开销,第二点,在很多地方用char数组代替了string。  
  HTTP 1.1 新特性:  
  1. 持久连接:这个我们比较熟悉,就是复用Connection,来下载多个资源;  
  2. 块编码: 在content-length没有准备好的情况下,每块数据都会提供一个length,     用来指示块长度;  
  3. 100状态码的使用, 这个一般用作client来确定服务器状态用的,这个一般用作客户端准备传送一个大的request body,但无法确定服务器是否接受它,如果服务器此刻是down的,那么客户端传送一个大的request body是一个资源浪费。  
  Connector接口:  
  1. Tomcat的连接器都是实现org.apache.catalina.Connector接口,它的主要的方法是getContainer, setContainer, createRequest,createResponse. setContainer会使一个Connector和一个Container联系起来,其他的createRequest和createResponse比较容易理解,就是创建一个Request和Response对象。  
  2. Org.apache.catalina.http.HttpConnector是它的实现类。下面我们看一下类图:  
  
  我们来看HttpConnector类 的实现吧:  
  首先在它的open方法里面调用ServerSocketFactory创建一个ServerSocket,DefaultServerSocketFactory实现ServerSocketFactory,这个很好理解,就是创建一个ServerSocket。  
  在第三章里面,我们的HttpConnector只有一个HttpProcessor实例,它一次只能请求一个Http请求,在Tomcat连接器里面,它有一个HttpProcessor对象池,每个HttpProcessor都在独自的线程里面运行,所以HttpProcessor可以同时处理多个Http请求。  
  HttpConnector维护了一个HttpProcessor池来避免HttpProcessor的创建, HttpProcessor实例是维护在一个栈中的,  
  Private Stack processors = new Stack();  
  在HttpConnector中有个minProcessors和maxProcessors两个变量,HttpConnector会创建minProcessors个HttpProcessor,它会创建HtttpProcessor,直到maxProcessors达到后。 变量curProcessor保存着HttpProcessor创建的数量。  
  在HttpConnector的start方法里面会调用下面的代码来创建初始的Processor。  
  While(curProcessors  0 && curProcessor >= maxProcessors){ Break; } HttpProcessor processor = newProcessor(); Recycle(processor); }  
  Recycle方法是将HttpProcessor压入到栈中去的。  
  HttpProcessor是负责解析HTTP Request请求头和Header的,一个HttpProcessor和一个request和一个response对象关联。 在HttpProcessor的构造函数里面会调用createRequest和createResponse方法来创建Request对象和Response对象。  
  当有一个请求来临时,HttpProcessor会从对象池中取得一个HttpProcessor对象,如果到达maxProcessors的时候,HttpConnector直接关闭socket,Http request将不会被处理。获得一个HttpProcessor方法后,将会调用HttpProcessor的assign方法:  
  Processor.assing(socket);  
  HttpProcessor对象是利用SocketInputStream读取请求头,解析Http Request。我们现在就来看一下assign方法吧。  
  /** * Process an incoming TCP/IP connection on the specified socket. Any * exception that occurs during processing must be logged and swallowed. * NOTE: 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 // 在创建的时候,available是false的,所以这个while循环将被跳过 while (available) { try { wait(); } catch (InterruptedException e) { } } // Store the newly available Socket and notify our thread // 我们将available设置成true,调用notifyAll来唤醒等待当前对象的锁 this.socket = socket; available = true; notifyAll(); if ((debug >= 1) && (socket != null)) log(" An incoming request is being assigned"); // 这个方法就可以返回了,HttpConnector就可以相应下一个请求了。 }  
  对了,我们要完全理解这个HttpProcessor线程,我们应该先看一下HttpConnector的newProcessor方法。  
  /** * Create and return a new processor suitable for processing HTTP * requests and returning the corresponding responses. */ private HttpProcessor newProcessor() { // if (debug >= 2) // log("newProcessor: Creating new processor"); // 首先会创建一个HttpProcessor对象 HttpProcessor processor = new HttpProcessor(this, curProcessors++); if (processor instanceof Lifecycle) { try { // 在这里调用了processor的start方法 ((Lifecycle) processor).start(); } catch (LifecycleException e) { log("newProcessor", e); return (null); } } created.addElement(processor); return (processor); }  
  其实HttpProcessor的构造函数很简单,主要会调用HttpConnector的createRequest和createResponse方法。  
  我们看到在创建HttpProcessor的时候会调用start方法,在start方法里面调用threadStart方法,在start线程里面将该线程设置成守护线程,然后调用start方法,实际上会执行现场的run方法,我们就重点看一下run方法吧。其实run方法很简单,就是得到一个socket,然后处理该socket,处理完毕之后调用HttpConnector的recycle方法,将该对象压入processors栈中。  
  /** * 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(); } }  
  下面最重要的就是await方法了,这个方法写的很巧妙。我们来看一下吧:  
  /** * Await a newly assigned Socket from our Connector, or null * if we are supposed to shut down. */ private synchronized Socket await() { // 在初始化的时候availabe是false,所以会调用wait方法 // Wait for the Connector to provide a new Socket while (!available) { try { wait(); } catch (InterruptedException e) { } } // 其实我们刚才也看到了,调用了assign方法后,available的值会变成true, // 然后将socket返回,我们可以看到在这里将socket赋给了一个局部变量 // 这一点非常高明,使得HttpProcessor可以复用了。 // 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); }

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-335472-1-1.html 上篇帖子: ActiveMq-JMS简单实例使用tomcat 下篇帖子: tomcat架构分析(valve源码导读)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表