標籤:realm ack valve let ring 監聽 cto cti 多個
從大學開始接觸java web的開發時就開始使用tomcat部署web項目,對它的理解僅僅停留在"這是個開源免費的servlet容器"的階段,後來也接觸了一些tomcat的體系,原理等方面的知識,也是半知半解,最近又開始看這方面的東西,截止到寫這篇博文,我也不沒有完全理解它,但一些比較基礎的東西總算有些眉目了,讀源碼不易,且行且珍惜,這裡寫篇筆記整理下.
Tomcat體繫結構
先盜張圖:
可以看到,Tomcat有一個最頂層的容器,也就是server容器,它最大,在server容器中,可以有多個service,由service來提供服務,所以service不能沒有,至少得有一個.
在service中,主要包含兩個組件,Connector和Container.Container中沒有標出,其實就是包含了Engine的部分.
Tomcat可以提供多種協議的請求,http協議就是其中一種,這裡以http請求為例,一個http請求發到伺服器時,由Connector來接收並進行轉換,Connector就是用來處理串連相關工作的組件,比如可以進行Socket與request,response之間的轉換,container是一個包含了servlet等眾多資源的庫,它接受Connector傳過來的request請求,解析出請求的資源,返回給Container,所以Connector和Container一個主外一個主內,兩人共同建立起美滿的家庭.
當然上述比喻是不嚴謹的,因為一個Service中只有一個Container,但卻可以有多個Connector,下面一段代碼來自Tomcat目錄下conf下的server.xml:
<Service name="Catalina"> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> </Service>
可以看到,預設的Tomcat服務組態檔有兩個Connector,一個負責監聽8080連接埠,一個負責監聽8009連接埠,前者我們很熟悉了,它用來監聽來自於瀏覽器的http請求,然後會new出一個線程來把請求傳給Engine,而後者則是用來監聽其他類型的servlet/jsp請求,叫AJP協議(我也沒聽說過).
Container體繫結構
繼續盜圖,Container的體繫結構:
Container是tomcat中容器的介面,我們最熟悉的Servlet就封裝在Container的子介面Wrapper中.看一下Server.xml中的配置:
<Service name="Catalina"> <Engine name="Catalina" defaultHost="localhost"> <Realm className="org.apache.catalina.realm.LockOutRealm"> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine> </Service>
Container有四個子容器,根據圖示以及xml配置就可以看出來他們是逐層包含的關係.
每個service中只有一個Engine,Engine中可以由多個Host,每個Host可以有多個Context,每個Context中可以有多個Wrapper,而每一個Wrapper裡面就封裝著一個Servlet.
下面分別簡單總結幾個容器:
Engine:顧名思義,引擎,它用來管理多個網站,也就是Host.
Host:表示一個網站,也可以叫做虛擬機器主機,在上面xml配置中,可以看到Tomcat預設配置了一個名為localhost的虛擬機器主機,我們部署,運行項目時,就預設進入這個網站,Tomcat回去webapps目錄下去定位請求的web項目資源.
Context:意思是上下文,它表示一個應用程式,也就是我們開發的一個web項目,一個web項目就可以理解為一個Context.
Wrapper:每個Wrapper封裝一個servlet.
預設配置下的webapps下的每一目錄都是一個應用,其中有一個ROOT目錄代表主應用,整個webapps表示一個網站(Host),當我們檢測tomcat是否啟動成功時一般都會開啟http://localhost:8080/,這時候如果出現tomcat的官方網站就表示啟動成功,其實這時候訪問的就是ROOT應用下的資源,主應用就是直接使用網域名稱訪問就可以,假設webapps下還有一個helloword目錄,如果你想訪問helloword目錄下的資源,就需要輸入http://localhost:8080/helloword/.
conf目錄下的設定檔server.xml
<Server port="8005" shutdown="SHUTDOWN"> <Service name="Catalina"> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> <Engine name="Catalina" defaultHost="localhost"> <Realm className="org.apache.catalina.realm.LockOutRealm"> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine> </Service></Server>
在server.xml 中首先配置了一個server,在8005連接埠監聽關閉命令"shutdown".
Server裡定義了一個名為Catania的Service,Service裡定義了兩個Connector,一個是HTTP協議,一個是AJP協議,此外還定義了一個名為Catalina的Engine,Engine裡定義了一個名為localhost的Host.
Host中name屬性工作表示網域名稱,所以這個預設Host可以用localhost來訪問,appBase屬性指定了網站的位置,這裡就是webapps目錄,這裡還有很多屬性,詳細介紹,可以參考這篇博文:http://www.blogjava.net/baoyaer/articles/107278.html
Container體繫結構
沒盜到圖,自己畫一張:
Connector是用來接收請求並把請求封裝成Request和Response來進行具體的業務處理的,底層使用的Socket串連.
Connector實現了TCP/IP協議和HTTP協議,他會把Request和Response按照HTTP協議來進行封裝,封裝完之後交給Container來進行處理,待Container處理完之後,再返回回來,Connector使用Socket將返回結果返回給瀏覽器,完成整個處理請求.
下面簡單介紹Connector中的幾個重要組件
ProtocolHandler:處理不同連線類型的請求,比如普通Socket請求和NioSocket請求.
Endpoint:處理底層Socket的網路連接.實現的是TCP/IP協議.
Processor:將Endpoint接收到的Socket請求封裝成Request,實現的HTTP協議.
Adapter: 將Request請求適配給Container來處理.
整個Tomcat伺服器其實就是java編寫的一個應用,我嘗試著讀了一些源碼,但資曆尚淺,讀的很艱難,一些代碼上的實現方式和原理也不懂,只能大概理解一些類的功能,所以這裡只是簡單總結一些比較膚淺的知識,以後,有決心和毅力再去研讀.共勉.
參考資料:
<看透Spring mvc源碼>第七章:Tomcat分析
重溫web伺服器--細說Tomcat伺服器