tomcat分配請求之——請求如何流程Connection

 

首先摘自我的好友。傻博語錄:人生就是悲劇

 

上次說到每一個請求會分配給一個Worker處理,而Worker與我們平時寫代碼都是圍繞Servlet寫的,到底又有些什麼差別呢?

worker後面是委託給Handler處理的。

handler處理的時候分配給Http11Processor(Http11Processor被維護在一個先進先出隊列當中)。

而所有的HttpProcessor共享Http11Protocal 的Adapter成員變量,Adapter會調用到Servlet,即所有Handler都用同一個Adapter。

首先請看圖:



 講述下每個部分的作用:

 

JioEndPointer:啓動一個線程監聽socket,並把到來的請求分配給相應的worker

Http11ConnectionHandler: Http協議的基於普通IO的處理方式.

Adapter:Http協議的請求 委託或 適配給 servlet容器處理的適配器

attributes:Http協議的相關屬性設置


其中的對應關係也非常重要:

A,1個worker 必須對應一個 Http11ConnectionHandler 中的Http11ConnectionProcessor(是handler裏面真正處理的Http協議的類)

 

B,所有的worker都持有同一個Adapter

 

 

 

詳細類圖下圖所示:

 



 

 

我在HttpServlet的service方法裏設置了一個斷點,然後調試了下,可以看一下調用棧。 

 調用棧很清晰得說明了調用到哪些類和順序:也可以看官方化得時序圖: 

http://tomcat.apache.org/tomcat-6.0-doc/architecture/requestProcess/requestProcess.pdf

 

 

 

JIoEndpoint.java

/** * Create (or allocate) and return an available processor for use in * processing a specific HTTP request, if possible. If the maximum * allowed processors have already been created and are in use, return * <code>null</code> instead. */ protected Worker createWorkerThread() { synchronized (workers) { if (workers.size() > 0) { curThreadsBusy++; return workers.pop(); } if ((maxThreads > 0) && (curThreads < maxThreads)) {              // 默認maxThreads 爲200 curThreadsBusy++; if (curThreadsBusy == maxThreads) { log.info(sm.getString("endpoint.info.maxThreads", Integer.toString(maxThreads), address, Integer.toString(port))); } return (newWorkerThread()); } else { if (maxThreads < 0) { curThreadsBusy++; return (newWorkerThread()); } else { return (null); } } } } /** * Create and return a new processor suitable for processing HTTP * requests and returning the corresponding responses. */ protected Worker newWorkerThread() { Worker workerThread = new Worker(); workerThread.start(); return (workerThread); }

 


 

從代碼來看,如果沒有到達請求最大值,首先會從棧中取得空閒的Worker,或者創建新的Worker。

 

所以來一個請求,會分配給一個Worker,而Worker做了一些接收Socket,設置一些socket和需要的環境類,然後就交給了Servlet實例,而servlet實例啓動的時候就是對於一個context 中配置的一個servlet只啓動一個實例。

 

 StandardWrapper.java

/** * Load and initialize an instance of this servlet, if there is not already * at least one initialized instance. This can be used, for example, to * load servlets that are marked in the deployment descriptor to be loaded * at server startup time. */ public synchronized Servlet loadServlet() throws ServletException { // Nothing to do if we already have an instance or an instance pool // 初始化servlet的時候,如果發現已經初始化完畢,則不再初始化 if (!singleThreadModel && (instance != null)) return instance;

 


 

所以首先servlet不是線程安全的。

其次 HttpSession不是線程安全的。

還有 Context不是現成安全的。

 

Request是線程安全的。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章