servlet解析演进(2-1)
2019獨角獸企業重金招聘Python工程師標準>>>
上文說了簡單的servlet解析過程。實際上,tomcat在解析servlet的 時候是吧連接器定位為滿足以下三個條件:
1、必須事先接口org.apache.catalina.Connector
2. 必須創建請求對象,該請求對象的類必須實現接口org.apache.catalina.Request。?
3. 必須創建響應對象,該響應對象的類必須實現接口org.apache.catalina.Response。
tomcat的連接器有很多種類:Coyote、mode_jk、mod_jk2和mode_webapp等。
來自瀏覽器的請求類型是有區別的http/0.9 http/1.0 http/1.1.
http/1.1又叫做持久連接,上文中一次請求處理完畢就關閉了socket。然而,在現實的頁面請求中需要加載多種資源(js、img css)。如果每次請求都開啟關閉連接那將是非常耗時的事情。http/1.1能夠讓瀏覽器和服務器保持一種持久化的連接,快速的相應請求。這樣,請求的形式就和之前不同,他是一塊編碼的形式,并使用特殊頭部transfer-encoding感知發送過來的數據信息。同時,如果瀏覽器有較大數據請求之前發送頭部信息Expect: 100-continue頭部到服務器,等待服務器的相應。如果服務器響應數據能夠接受大數據請求,才真正的發送數據,避免先發送大數據而遭服務器拒絕而浪費了傳輸數據的帶寬資源。
本文重點說明連接器的演進。
連接器的演進主要包括了以下幾個方面:
1、處理請求不再只是一次處理一次請求,而是生成Processor池,用于處理多個連接請求。同事Processor處理器也不再是每次請求新生成實例處理請求,而是從池子中獲取到一個處理器去完成請求。同時,實現了Processor處理方法異步化,讓連接器線程能夠繼續接受其他的請求。
2、處理器線程和連接器線程通過wait() notifyAll()的方式進行線程間通信。
3、Processor處理器中,增加了標識符,KeepAlive、stopped和http11,為處理器在處理的過程中設定“路口”,及時相應請求的變化。
4、socket緩沖區大小不再是像前文一樣設置為定值,而是通過獲取連接器傳遞過來的參數設置緩沖區大小。
5、處理器的職能更加的豐富。
連接處理 ?parseConnection,針對不同的連接協議做不同的處理。
解析請求 parseRequest
解析頭部 parseHeaders?
6、去掉了靜態處理器,暫時無法接受靜態資源請求。
------------------------
1、連接器啟動:
HttpConnector?connector?=?new?HttpConnector(); SimpleContainer?container?=?new?SimpleContainer(); connector.setContainer(container); try?{ //初始化連接器,打開socket連接 connector.initialize(); //開啟監聽,開啟連接器線程、將處理器線程啟動并入隊列。 connector.start();System.in.read(); } catch?(Exception?e)?{e.printStackTrace(); }1.1 初始化連接、打開socket連接(使用工廠模式)
public?void?initialize() throws?LifecycleException?{ //初始化標志,不能重復初始化 if?(initialized) throw?new?LifecycleException?( sm.getString("httpConnector.alreadyInitialized")); this.initialized=true;Exception?eRethrow?=?null; //?Establish?a?server?socket?on?the?specified?port try?{ //打開socket連接 serverSocket?=?open();}?catch?(IOException?ioe)?{log("httpConnector,?io?problem:?",?ioe);eRethrow?=?ioe;}?catch?(KeyStoreException?kse)?{log("httpConnector,?keystore?problem:?",?kse);eRethrow?=?kse;}?catch?(NoSuchAlgorithmException?nsae)?{log("httpConnector,?keystore?algorithm?problem:?",?nsae);eRethrow?=?nsae;}?catch?(CertificateException?ce)?{log("httpConnector,?certificate?problem:?",?ce);eRethrow?=?ce;}?catch?(UnrecoverableKeyException?uke)?{log("httpConnector,?unrecoverable?key:?",?uke);eRethrow?=?uke;}?catch?(KeyManagementException?kme)?{log("httpConnector,?key?management?problem:?",?kme);eRethrow?=?kme;} if?(?eRethrow?!=?null?) throw?new?LifecycleException(threadName?+?".open",?eRethrow); } private?ServerSocket?open() throws?IOException,?KeyStoreException,?NoSuchAlgorithmException,CertificateException,?UnrecoverableKeyException,KeyManagementException { //?Acquire?the?server?socket?factory?for?this?Connector//獲得服務器socket工廠實例 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);}}? //在指定地址上打開一個連接 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);}} }1.2、開啟監聽,開啟連接器線程、將處理器線程啟動并入隊列。
//為連接器綁定指定數量的處理器 public?void?start()?throws?LifecycleException?{???? //判斷該線程的connect開啟狀態,避免重復開啟 if?(started) throw?new?LifecycleException(sm.getString("httpConnector.alreadyStarted")); threadName?=?"HttpConnector["?+?port?+?"]"; //打開監聽 lifecycle.fireLifecycleEvent(START_EVENT,?null); started?=?true; //?Start?our?background?thread//開啟一個后臺連接器線程 threadStart(); //創建處理器,并調用recyle方法將其放置到棧隊列中 while?(curProcessors?<?minProcessors)?{ if?((maxProcessors?>?0)?&&?(curProcessors?>=?maxProcessors)) break;HttpProcessor?processor?=?newProcessor();recycle(processor);} }2、連接器、容器之間的協作關系
2.1 容器派發socket到處理器線程
2.2處理器接收到派發socket
synchronized?void?assign(Socket?socket)?{ //?d等待該處理器的其它socket處理執行完畢 while?(available)?{ try?{wait();}?catch?(InterruptedException?e)?{}} //?Store?the?newly?available?Socket?and?notify?our?thread//將新獲取的socket放置到處理器中,并發送線程通知 this.socket?=?socket; available?=?true;notifyAll(); if?((debug?>=?1)?&&?(socket?!=?null))log("?An?incoming?request?is?being?assigned"); }2.3 ?處理器接收到了socket請求,準備處理
public?void?run()?{ //?Process?requests?until?we?receive?a?shutdown?signal while?(!stopped)?{ //?Wait?for?the?next?socket?to?be?assigned//等待連接器的socket請求 Socket?socket?=?await(); if?(socket?==?null) continue; //?Process?the?request?from?this?socket try?{ //處理socket請求 process(socket);}?catch?(Throwable?t)?{log("process.invoke",?t);} //?Finish?up?this?request//處理完畢,將該processor線程歸還給Stack?processors?用來處理接下來的socket請求 connector.recycle(this);} //?Tell?threadStop()?we?have?shut?ourselves?down?successfully synchronized?(threadSync)?{ //該處理器線程退出,通知其他processor threadSync.notifyAll();} }未完待續
轉載于:https://my.oschina.net/zjItLife/blog/608576
總結
以上是生活随笔為你收集整理的servlet解析演进(2-1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 差分约束 4416 FFF 团卧底的后
- 下一篇: 华硕P8B-C/2L及其他