国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從Servlet講到Tomcat

Little_XM / 3297人閱讀

摘要:在組件樹中前面啟動的過程中提到過的的線程負責接收連接,接收請求之后調用方法,把包裝成,創建一個任務,從線程池中獲取一個線程處理該任務。

概念

Java Web,是基于Java語言實現web服務的技術總和。介于現在Java在web客戶端應用的比較少,我把學習重點放在了JavaWeb服務端應用。雖然用Springboot就可以很快地搭建一個web項目了,但是如果想要深入了解JavaWeb的實現原理,就不得不先學習Servlet和Servlet容器的相關知識。

首先什么是Servlet?

Servlet從廣義上講是Sun公司提供的一門用于開發動態Web資源的技術,而狹義上指的是實現了javax.servlet.Servlet接口的類的統稱。Servlet接口很簡單,只有init、getServletConfig、service、getServletInfo和destroy這5個方法,它們構成了實現Servlet功能的規范。像Spring的DispatcherServlet,都是一種具體的Servlet。

當然了,光有Servlet這一個類可沒什么用,它沒有main方法,不能獨立運行,就像光有子彈沒有槍,子彈的價值就發揮不出來。要想實現Servlet的功能,就必須有一個Servlet容器。

Servlet容器,也叫做Servlet引擎,是web服務器的一部分,用于接收網絡請求,把請求轉發給對應的Servlet,并把Servlet處理的結果返回給網絡。

它是web服務器和Servlet之間的媒介。

它建立服務端socket、監聽端口、創建流。

它管理著Servlet的生命周期,如加載部署Servlet,實例化初始化Servlet,調用Servlet方法(處理業務),以及銷毀Servlet。

Tomcat就是一個獨立運行的Servlet容器。

Tomcat組織結構

下面就以Tomcat8為例,看看一個具體的Servlet容器是如何實現上述功能的。

先來一張Tomcat的結構圖:

Server:Tomcat頂層容器,代表著整個服務器。包含一個或多個Service組件;

Service:存活在Server內部的中間組件,包含Connector和Container這兩個核心組件,負責將一個或多個Connector組件綁定到一個Container上;

Connector:監聽端口,處理與客戶端基于某種協議的通信,提供Socket與request和response的轉換;

Container:封裝和管理Servlet,負責對請求進行處理,并生成響應。

(先介紹這幾個大的組件,小組件在后面會細講)

這樣展示可能比較抽象,我們可以打開我們安裝的Tomcat目錄下的conf/server.xml,看下Tomcat是如何配置這些組件的:

 

     

         



         

             

                ...

             

     

     

 

先看Connector,可以看到一個Service里是可以配置多個Connector的,這里我們主要關心HTTP協議的Connector。

Connector使用持有的ProtocolHandler類型對象來處理請求,它包含的三個部件:

Endpoint:綁定端口、監聽請求;

Processor:將Endpoint接收到的Socket封裝成Request;

Adapter:將Request交給Container進行具體的處理。

再看Container,它內部包含了4個子容器

Engine:Servlet引擎,Container最上層,每個Service只能包含一個,表示一個特定的Service的請求處理流水線,從Connector接收處理所有的請求并返回響應;

Host:虛擬主機,一個引擎可以包含多個Host;一個Host可以包含多個Context;

Context:一個Context表示了一個Web應用程序(Web工程)。Context直接管理Servlet在容器中的包裝類;

Wrapper:每一個Servlet在容器中的包裝類。

我們可以通過Tomcat文件夾里的文件結構來幫助理解,上面提到的conf/server.xml里配置Host時有個appBase的屬性是webapps,是不是很眼熟?我們在Tomcat安裝目錄下總是有一個webapp文件夾,整個webapps就是一個Host站點,里面放著的每個文件夾目錄就對應一個Context,其中ROOT目錄中存放著主應用,其他目錄存放著子應用。

Tomcat類加載

先看Tomcat是如何加載類的。

Tomcat啟動時創建的類加載器有

BootstrapClassLoader:加載JVM提供的基本運行類,和$JAVA_HOME/jre/lib/ext里的jar包;

SystemClassLoader:加載tomcat啟動的類,即Catalina.bat中指定位置的類;

CommonClassLoader:加載tomcat以及應用通用的類,位于CATALINA_HOME/lib下。父加載器是AppClassLoader;

WebAppClassLoader:每個應用在部署后都創建一個唯一的類加載器,加載位于WEB-INF/lib中的jar包和WEB-INF/classes下的class文件。父加載器是CommonClassLoader。

Tomcat默認類加載邏輯:

1、先在本地緩存中查找,如果已經加載即返回,否則繼續下一步

2、嘗試Bootstrap加載,如果加載到即返回,否則

3、WebApp自行加載,先/WEB-INF/classes,再/WEB-INF/lib/*.jar,如果加載到即返回,否則

4、委托WebApp父類加載器(Common ClassLoader)去加載。。。

注意:第3、4兩步違反了雙親委托機制,但也只是Tomcat自定義的ClassLoader加載順序違反了,頂層還是相同的。

Tomcat的這種加載邏輯保證了每個應用程序的同名類庫是獨立的,同時可以共享共有類庫。

每一個JSP文件對應一個Jsp類加載器,當一個jsp文件修改了,就直接卸載這個jsp類加載器,重新創建類加載器,重新加載jsp文件。

Tomcat啟動流程

下面開始分析Tomcat大致啟動流程,建議配合源碼食用。

Tomcat傳統的啟動入口通過startup.bat和catalina.bat腳本調用org.apache.catalina.startup.Bootstrap.main(),分為兩部分:

一、init():初始化main線程的daemon(一個Bootstrap對象)。初始化Tomcat類加載器,通過反射來實例化Catalina對象;

二、daemon執行三個方法setAwait(true)、load(args)和start():

1、setAwait:通過反射調用catalina的setAwait方法設置await屬性,后面會用到;

2、load(args):通過反射調用catalina的load方法,創建xml解析器,解析conf/server.xml創建出了StandardServer對象并init,繼而調用內部包含的service的int,以此逐層初始化所有組件;

3、start():通過反射調用catalina的start()方法,和init方法一樣逐層start所有組件;最后利用前面設置的await屬性調用await方法,繼而調用server的await方法,保證主線程運行并持續監聽8005端口的SHUTDOWN指令,接收到后調用stop方法關閉Tomcat。

上面各個組件的init和start都是一筆帶過,那么他們實際完成了什么樣的工作呢?

Server.init():調用包含的Service的init;

Service.init():初始化Engine,初始化Executor(所有Connector共享的線程池),初始化mapperListener(用來保存容器映射),調用Connector.init;

Connector.init():初始化ProtocolHandler、Adapter,Endpoint創建ServerSocket并綁定監聽端口

Server.start():調用包含的Services的start;

Service.start():與初始化對應,調用Engine.start,啟動Executor,啟動mapperListener(作為監聽者加到容器和它們的子容器中),調用Connector.start

Connector.start():Endpoint創建acceptor線程來接收客戶端的連接以及poller線程來處理連接中的讀寫請求

Engine.start():逐一啟動Host、Context、Wrapper

Context.start():步驟很多,這里列舉幾個重要的:

*)創建讀取資源文件的對象

*)創建ClassLoader對象,就是上面提到過的每個應用唯一的WebAppClassLoader

*)設置應用的工作目錄

*)啟動相關輔助對象,如Logger、realm、resources等

*)通知監聽者ContextConfig讀取和解析Web應用web.xml和注解

*)啟動web.xml解析到的子容器(解析時將Servlet包裝成StandardWrapper)

*)啟動Pipeline(一種責任鏈設計模式后面會講)

*)獲取或創建ServletContext,并設置必要的參數

*)創建Context中配置的Listener;

*)創建和初始化配置的Filter;

*)創建和初始化loadOnStartup大于等于0的Servlet

Tomcat處理請求過程

現在我們知道Tomcat是如何啟動的,那么啟動之后Tomcat如何處理一次請求的呢?

下面以一次Http請求為例來說明,請求URL=http://hostname:port/contextpath/servletpath。

在Connector組件樹中:

前面啟動的過程中提到過Connector的Endpoint的acceptor線程負責接收Socket連接,acceptor接收請求之后調用processSocket方法,把socket包裝成SocketWrapper,創建一個SocketProcessor任務,從線程池中獲取一個線程處理該任務。run方法中調用AbstractEndpoint.Handler.process方法,根據請求的協議類型(con/server.xml中connector元素的protocol屬性值)創建相應的類型處理類Processor,對SocketWrapper的輸入流和輸出流進行包裝,根據SocketWrapper創建輕量級的coyote.Request和coyote.Response,解析http請求的請求頭和請求行,最后Adapter.service(Request, Response),將coyote.Request和coyote.Response轉化成Connector.Request和Connector.Response,調用connector.getService().getMapper().map(),根據hostname、contextpath和servletpath找到對應的host、context和Wapper(前面利用mapperListener保存的容器完整關系),設置到Request中去;再調用connector.getService().getContainer().getPipeline().getFirst().invoke(request, response)將請求傳遞給與Connector關聯的Container逐級傳遞下去(Engine->Host->Context->Wapper)。

在Container組件樹中:

Container容器按照責任鏈的設計模式,使用管道Pipeline和Value的方式來傳遞請求。

第一層是Engine,先通過conf/server.xml中配置的value,最后總會流到StandardEngineValue,調用host.getPipeline().getFirst().invoke(request, response)將請求傳遞給request中保存的Host;

第二層是Host,同樣先通過配置的value,最后流到StandardHostValue,再傳遞給request中保存的Context;

第三層是Context,流到StandardContextValue傳遞給request中保存的Wapper;

最后是Wapper,流到StandardWapperValue,獲取Servlet單例(雙檢查鎖機制),獲取FilterChain執行Filter鏈,也是一種責任鏈模式,執行完所有配置的Filter后執行Servlet.service,即我們希望其完成的業務邏輯。

(在進入Filter的時候,傳入的是Connector.Request的門面類RequestFacade,和Request一樣都是HttpServletRequest和HttpServletResponse的實現類)

返回過程略。

第一次寫文章,條理排版不是很清晰,以后慢慢改進。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72314.html

相關文章

  • Servlet第四篇【request對象常用方法、應用】

    摘要:瀏覽器的中文數據提交給服務器,以編碼對中文編碼,當我在讀取數據的時候,拿到的當然是亂碼。接下來使用方式傳遞中文數據,把表單的方式改成即可當我們訪問的時候,又出現亂碼了于是我按照上面的方式,把對象設置編碼為試試結果還是亂碼。 什么是HttpServletRequest HttpServletRequest對象代表客戶端的請求,當客戶端通過HTTP協議訪問服務器時,HTTP請求頭中的所有信...

    raise_yang 評論0 收藏0

發表評論

0條評論

Little_XM

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<