How Tomcat works — 六、tomcat處理請求,tomcatworks
tomcat已經啟動完成了,那麼是怎麼處理請求的呢?怎麼到了我們所寫的servlet的呢?
目錄
- Http11ConnectionHandler
- Http11Processor
- CoyoteAdapter
- StandardEngineValve
- StandardWrapperValve
- 總結
Http11ConnectionHandler
在tomcat 啟動之後會使用socket.accept接收請求,接收到之後會調用自己的processSocket來處理請求,在該方法中啟動一個SocketProcessor線程,在該內部類的潤方法內調用Http11ConnectionHandler.process,過程如下:
實際執行的是超類AbstractConnectionHandler.process方法,主要作用:
- 從connections裡面獲取processor
- 如果processor為null則嘗試從隊列裡面獲取一個processor,該隊列是一個RecycledProcessors類繼承自ConcurrentLinkedQueue,是一個線程安全的隊列,因為同時會有多個線程獲取processor
- 如果processor還是為null(表明還未創建或者已經用完),那麼創建一個新的processor,調用Http11ConnectionHandler.createProcessor,該方法會創建一個新的Http11Processor(但是並不會立即添加到上面提到的隊列裡面,而是在請求處理完成之後才會添加到隊列裡面)
- 調用Http11Processor.process
Http11Processor
在connector出來完成之後會啟動processor線程,關於processor的類圖如下:
和處理協議一 一對應,不同的協議也有不同的processor,在AbstractProcessor裡面有Request和Response,不過是org.apache.coyote包下面的,這是在connector層面的連接器,是primitive的。
實際執行的也是超類AbstractHttp11Processor.process,主要功能如下:
- 獲得socket的輸入、輸出流
- parsing request header、method、requestURI
- 設置request filters,並設置content-length等header
- 調用CoyoteAdapter.service
CoyoteAdapter
由connector和processor過渡到container的類,使用了adapter模式,將container適配到processor。主要的方法就是CoyoteAdapter.service:
- 獲取org.apache.connector.Request和Response,這兩個類經過facade模式之後就是最後我們servlet中使用的request和response
- 如果是新建的processor,request和response為null,那麼就調用connector.createRequest和createResponse新建,然後設置到coyote.request的note中
- 調用postParseRequest,添加wrapper和servlet之間的映射(在後面load servlet的時候用到),parseSessionId解析sessionId
- connector.getService().getContainer().getPipeline().getFirst().invoke(request, response),依次是:Connector,StandardService,StandardEngine,StandardPipeline,StandardEngineValve
- 在執行完之後,完成請求也在這個方法中:request.finishRequest(上面說過的processor就是在這兒回收的),response.finishResponse(請求在這裡返回到客戶端,outputStream)
- 最後,recycle request和response,清空request和response所有信息
StandardEngineValve
這個是StandardEngine的基礎閥(每個容器都有一個pipeline,每個pipeline都有一個基礎閥,用來調用servlet)在adapter中最後調用到了StandardEngineValve.invoke方法,該方法主要進行了以下操作
- request.getHost:獲取host
- host.getPipeline().getFirst().invoke(request, response):依次是StandardHost,StandardPipeline,StandardHostValve
接下來就是容器逐級依次調用,下一個是StandardHostValve:
context.getPipeline().getFirst().invoke(request, response);
在接下來是NonloginAuthencator
context.invokeNext(request,response)
接著是StandardContextValve
wrapper.getPipeline().getFirst().invoke(request, response);
接下來就是StandardWrapperValve,在這裡進行了很多工作。
StandardWrapperValve
這是StandardWrapper的基礎閥,作用就是獲取servlet實例並調用filterChain,主要方法是invoke:
- 獲取容器wrapper,通過wrapper分配一個servlet實例
- 使用ApplicationFilterFactory創建filterChain
- filterChain.doFilter調用filter鏈,這裡沒有配置額外的filter,只有一個默認的WsFilter(對websocket的支持),在所有的filterChain調用完成之後,就是調用servlet.service 方法,開始進入我們寫的servlet裡面
- 在上面調用完成之後,釋放filterChain(將filter置空),釋放servlet(會受到instantPool裡面)
這個執行流程如上,最後一個UserServlet是我自定義的簡單的servlet。到了自定義的servlet之後,依次請求也就是到了最深層,接下來就是逐層范返回,並做一些清理工作(當然了還有一些長連接的維護等等)。
總結
從socket監聽接收開始,到我們自定義的servlet處理請求結束,是一次完整的請求過程,為了說明白請求的整個過程,省略了很多細節,比如:三種request(coyote.Request,connector.Request,RequestFacade)之間的轉換,session的管理等等。