一:Tomcat核心元件及應用架構詳解 - tw511教學網

文章推薦指數: 80 %
投票人數:10人

Servlet 容器. Web 應用. 擴充套件機制. 一、Tomcat各元件認知. 2.Tomcat 各元件及關係. 二、Tomcat server.xml 設定詳解. 三、Tomcat 部署指令碼編寫 ... 技術文章»一:Tomcat核心元件及應用架構詳解 一:Tomcat核心元件及應用架構詳解 2021-05-2708:00:08 目錄 Web容器是什麼? HTTP的本質 HTTP請求響應範例 Cookie和Session Servlet規範 Servlet容器 Web應用 擴充套件機制 一、Tomcat各元件認知 2.Tomcat各元件及關係 二、Tomcatserver.xml設定詳解 三、Tomcat部署指令碼編寫 Web容器是什麼? 讓我們先來簡單回顧一下Web技術的發展歷史,可以幫助你理解Web容器的由來。

早期的Web應用主要用於瀏覽新聞等靜態頁面,HTTP伺服器(比如Apache、Nginx)向瀏覽器返回靜態HTML,瀏覽器負責解析HTML,將結果呈現給使用者。

隨著網際網路的發展,我們已經不滿足於僅僅瀏覽靜態頁面,還希望通過一些互動操作,來獲取動態結果,因此也就需要一些擴充套件機制能夠讓HTTP伺服器呼叫伺服器端程式。

於是Sun公司推出了Servlet技術。

你可以把Servlet簡單理解為執行在伺服器端的Java小程式,但是Servlet沒有main方法,不能獨立執行,因此必須把它部署到Servlet容器中,由容器來範例化並呼叫Servlet。

而Tomcat就是一個Servlet容器。

為了方便使用,它們也具有HTTP伺服器的功能,因此Tomcat就是一個「HTTP伺服器+Servlet容器」,我們也叫它們Web容器。

  HTTP的本質 HTTP協定是瀏覽器與伺服器之間的資料傳送協定。

作為應用層協定,HTTP是基於TCP/IP協定來傳遞資料的(HTML檔案、圖片、查詢結果等),HTTP協定不涉及封包(Packet)傳輸,主要規定了使用者端和伺服器之間的通訊格式。

假如瀏覽器需要從遠端HTTP伺服器獲取一個HTML文字,在這個過程中,瀏覽器實際上要做兩件事情。

與伺服器建立Socket連線。

生成請求資料並通過Socket傳送出去。

HTTP請求響應範例 使用者在登陸頁面輸入使用者名稱和密碼,點選登陸後,瀏覽器發出了這樣的HTTP請求: HTTP請求資料由三部分組成,分別是請求行、請求報頭、請求正文。

當這個HTTP請求資料到達Tomcat後,Tomcat會把HTTP請求資料位元組流解析成一個Request物件,這個Request物件封裝了HTTP所有的請求資訊。

接著Tomcat把這個Request物件交給Web應用去處理,處理完後得到一個Response物件,Tomcat會把這個Response物件轉成HTTP格式的響應資料並行送給瀏覽器。

HTTP的響應也是由三部分組成,分別是狀態行、響應報頭、報文主體。

同樣,我還以極客時間登陸請求的響應為例。

Cookie和Session 我們知道,HTTP協定有個特點是無狀態,請求與請求之間是沒有關係的。

這樣會出現一個很尷尬的問題:Web應用不知道你是誰。

因此HTTP協定需要一種技術讓請求與請求之間建立起聯絡,並且伺服器需要知道這個請求來自哪個使用者,於是Cookie技術出現了。

Cookie是HTTP報文的一個請求頭,Web應用可以將使用者的標識資訊或者其他一些資訊(使用者名稱等)儲存在Cookie中。

使用者經過驗證之後,每次HTTP請求報文中都包含Cookie,這樣伺服器讀取這個Cookie請求頭就知道使用者是誰了。

Cookie本質上就是一份儲存在使用者原生的檔案,裡面包含了每次請求中都需要傳遞的資訊。

由於Cookie以明文的方式儲存在本地,而Cookie中往往帶有使用者資訊,這樣就造成了非常大的安全隱患。

而Session的出現解決了這個問題,Session可以理解為伺服器端開闢的儲存空間,裡面儲存了使用者的狀態,使用者資訊以Session的形式儲存在伺服器端。

當使用者請求到來時,伺服器端可以把使用者的請求和使用者的Session對應起來。

那麼Session是怎麼和請求對應起來的呢?答案是通過Cookie,瀏覽器在Cookie中填充了一個SessionID之類的欄位用來標識請求。

具體工作過程是這樣的:伺服器在建立Session的同時,會為該Session生成唯一的SessionID,當瀏覽器再次傳送請求的時候,會將這個SessionID帶上,伺服器接受到請求之後就會依據SessionID找到相應的Session,找到Session後,就可以在Session中獲取或者新增內容了。

而這些內容只會儲存在伺服器中,發到使用者端的只有SessionID,這樣相對安全,也節省了網路流量,因為不需要在Cookie中儲存大量使用者資訊。

那麼Session在何時何地建立呢?當然還是在伺服器端程式執行的過程中建立的,不同語言實現的應用程式有不同的建立Session的方法。

在Java中,是Web應用程式在呼叫HttpServletRequest的getSession方法時,由Web容器(比如Tomcat)建立的。

Tomcat的Session管理器提供了多種持久化方案來儲存Session,通常會採用高效能的儲存方式,比如Redis,並且通過叢集部署的方式,防止單點故障,從而提升高可用。

同時,Session有過期時間,因此Tomcat會開啟後臺執行緒定期的輪詢,如果Session過期了就將Session失效。

Servlet規範 HTTP伺服器怎麼知道要呼叫哪個Java類的哪個方法呢。

最直接的做法是在HTTP伺服器程式碼裡寫一大堆ifelse邏輯判斷:如果是A請求就調X類的M1方法,如果是B請求就調Y類的M2方法。

但這樣做明顯有問題,因為HTTP伺服器的程式碼跟業務邏輯耦合在一起了,如果新加一個業務方法還要改HTTP伺服器的程式碼。

那該怎麼解決這個問題呢?我們知道,面向介面程式設計是解決耦合問題的法寶,於是有一夥人就定義了一個介面,各種業務類都必須實現這個介面,這個介面就叫Servlet介面,有時我們也把實現了Servlet介面的業務類叫作Servlet。

但是這裡還有一個問題,對於特定的請求,HTTP伺服器如何知道由哪個Servlet來處理呢?Servlet又是由誰來範例化呢?顯然HTTP伺服器不適合做這個工作,否則又和業務類耦合了。

於是,還是那夥人又發明了Servlet容器,Servlet容器用來載入和管理業務類。

HTTP伺服器不直接跟業務類打交道,而是把請求交給Servlet容器去處理,Servlet容器會將請求轉發到具體的Servlet,如果這個Servlet還沒建立,就載入並範例化這個Servlet,然後呼叫這個Servlet的介面方法。

因此Servlet介面其實是Servlet容器跟具體業務類之間的介面。

下面我們通過一張圖來加深理解。

Servlet介面和Servlet容器這一整套規範叫作Servlet規範。

Tomcat和Jetty都按照Servlet規範的要求實現了Servlet容器,同時它們也具有HTTP伺服器的功能。

作為Java程式設計師,如果我們要實現新的業務功能,只需要實現一個Servlet,並把它註冊到Tomcat(Servlet容器)中,剩下的事情就由Tomcat幫我們處理了。

Servlet介面定義了下面五個方法: publicinterfaceServlet{ voidinit(ServletConfigconfig)throwsServletException; ServletConfiggetServletConfig(); voidservice(ServletRequestreq,ServletResponseres)throwsServletException,IOException; StringgetServletInfo(); voiddestroy(); } 其中最重要是的service方法,具體業務類在這個方法裡實現處理邏輯。

這個方法有兩個引數:ServletRequest和ServletResponse。

ServletRequest用來封裝請求資訊,ServletResponse用來封裝響應資訊,因此本質上這兩個類是對通訊協定的封裝。

HTTP協定中的請求和響應就是對應了HttpServletRequest和HttpServletResponse這兩個類。

你可以通過HttpServletRequest來獲取所有請求相關的資訊,包括請求路徑、Cookie、HTTP頭、請求引數等。

此外,我們還可以通過HttpServletRequest來建立和獲取Session。

而HttpServletResponse是用來封裝HTTP響應的。

你可以看到介面中還有兩個跟生命週期有關的方法init和destroy,這是一個比較貼心的設計,Servlet容器在載入Servlet類的時候會呼叫init方法,在解除安裝的時候會呼叫destroy方法。

我們可能會在init方法裡初始化一些資源,並在destroy方法裡釋放這些資源,比如SpringMVC中的DispatcherServlet,就是在init方法裡建立了自己的Spring容器。

你還會注意到ServletConfig這個類,ServletConfig的作用就是封裝Servlet的初始化引數。

你可以在web.xml給Servlet設定引數,並在程式裡通過getServletConfig方法拿到這些引數。

我們知道,有介面一般就有抽象類,抽象類用來實現介面和封裝通用的邏輯,因此Servlet規範提供了GenericServlet抽象類,我們可以通過擴充套件它來實現Servlet。

雖然Servlet規範並不在乎通訊協定是什麼,但是大多數的Servlet都是在HTTP環境中處理的,因此Servet規範還提供了HttpServlet來繼承GenericServlet,並且加入了HTTP特性。

這樣我們通過繼承HttpServlet類來實現自己的Servlet,只需要重寫兩個方法:doGet和doPost。

Servlet容器 當客戶請求某個資源時,HTTP伺服器會用一個ServletRequest物件把客戶的請求資訊封裝起來,然後呼叫Servlet容器的service方法,Servlet容器拿到請求後,根據請求的URL和Servlet的對映關係,找到相應的Servlet,如果Servlet還沒有被載入,就用反射機制建立這個Servlet,並呼叫Servlet的init方法來完成初始化,接著呼叫Servlet的service方法來處理請求,把ServletResponse物件返回給HTTP伺服器,HTTP伺服器會把響應傳送給使用者端 Web應用 Servlet容器會範例化和呼叫Servlet,那Servlet是怎麼註冊到Servlet容器中的呢?一般來說,我們是以Web應用程式的方式來部署Servlet的,而根據Servlet規範,Web應用程式有一定的目錄結構,在這個目錄下分別放置了Servlet的類檔案、組態檔以及靜態資源,Servlet容器通過讀取組態檔,就能找到並載入Servlet。

Web應用的目錄結構大概是下面這樣的: |-MyWebApp |-WEB-INF/web.xml--組態檔,用來設定Servlet等 |-WEB-INF/lib/--存放Web應用所需各種JAR包 |-WEB-INF/classes/--存放你的應用類,比如Servlet類 |-META-INF/--目錄存放工程的一些資訊 Servlet規範裡定義了ServletContext這個介面來對應一個Web應用。

Web應用部署好後,Servlet容器在啟動時會載入Web應用,併為每個Web應用建立唯一的ServletContext物件。

你可以把ServletContext看成是一個全域性物件,一個Web應用可能有多個Servlet,這些Servlet可以通過全域性的ServletContext來共用資料,這些資料包括Web應用的初始化引數、Web應用目錄下的檔案資源等。

由於ServletContext持有所有Servlet範例,你還可以通過它來實現Servlet請求的轉發。

擴充套件機制 引入了Servlet規範後,你不需要關心Socket網路通訊、不需要關心HTTP協定,也不需要關心你的業務類是如何被範例化和呼叫的,因為這些都被Servlet規範標準化了,你只要關心怎麼實現的你的業務邏輯。

這對於程式設計師來說是件好事,但也有不方便的一面。

所謂規範就是說大家都要遵守,就會千篇一律,但是如果這個規範不能滿足你的業務的個性化需求,就有問題了,因此設計一個規範或者一箇中介軟體,要充分考慮到可延伸性。

Servlet規範提供了兩種擴充套件機制:Filter和Listener。

Filter是過濾器,這個介面允許你對請求和響應做一些統一的客製化化處理,比如你可以根據請求的頻率來限制存取,或者根據國家地區的不同來修改響應內容。

過濾器的工作原理是這樣的:Web應用部署完成後,Servlet容器需要範例化Filter並把Filter連結成一個FilterChain。

當請求進來時,獲取第一個Filter並呼叫doFilter方法,doFilter方法負責呼叫這個FilterChain中的下一個Filter。

Listener是監聽器,這是另一種擴充套件機制。

當Web應用在Servlet容器中執行時,Servlet容器內部會不斷的發生各種事件,如Web應用的啟動和停止、使用者請求到達等。

Servlet容器提供了一些預設的監聽器來監聽這些事件,當事件發生時,Servlet容器會負責呼叫監聽器的方法。

當然,你可以定義自己的監聽器去監聽你感興趣的事件,將監聽器設定在web.xml中。

比如Spring就實現了自己的監聽器,來監聽ServletContext的啟動事件,目的是當Servlet容器啟動時,建立並初始化全域性的Spring容器。

Tomcat下載地址:https://tomcat.apache.org/download-80.cgi /bin:存放Windows或Linux平臺上啟動和關閉Tomcat的指令碼檔案。

/conf:存放Tomcat的各種全域性組態檔,其中最重要的是server.xml。

/lib:存放Tomcat以及所有Web應用都可以存取的JAR檔案。

/logs:存放Tomcat執行時產生的紀錄檔檔案。

/work:存放JSP編譯後產生的Class檔案。

/webapps:Tomcat的Web應用目錄,預設情況下把Web應用放在這個目錄下。

開啟Tomcat的紀錄檔目錄,也就是Tomcat安裝目錄下的logs目錄。

Tomcat的紀錄檔資訊分為兩類:一是執行紀錄檔,它主要記錄執行過程中的一些資訊,尤其是一些異常錯誤紀錄檔資訊;二是存取紀錄檔,它記錄存取的時間、IP地址、存取的路徑等相關資訊。

catalina.***.log主要是記錄Tomcat啟動過程的資訊,在這個檔案可以看到啟動的JVM引數以及作業系統等紀錄檔資訊。

catalina.out是Tomcat的標準輸出(stdout)和標準錯誤(stderr),這是在Tomcat的啟動指令碼裡指定的,如果沒有修改的話stdout和stderr會重定向到這裡。

所以在這個檔案裡可以看到我們在MyServlet.java程式裡列印出來的資訊localhost.**.log主要記錄Web應用在初始化過程中遇到的未處理的異常,會被Tomcat捕獲而輸出這個紀錄檔檔案。

localhost_access_log.**.txt存放存取Tomcat的請求紀錄檔,包括IP地址以及請求的路徑、時間、請求協定以及狀態碼等資訊。

manager.***.log/host-manager.***.log存放Tomcat自帶的Manager專案的紀錄檔資訊。

概要: Tomcat各核心元件認知server.xml設定詳解 一、Tomcat各元件認知 知識點: Tomcat架構說明Tomcat元件及關係詳情介紹Tomcat啟動引數說明Tomcat架構說明 Tomcat是一個基於JAVA的WEB容器,其實現了JAVAEE中的Servlet與jsp規範,與Nginxapache伺服器不同在於一般用於動態請求處理。

在架構設計上採用面向元件的方式設計。

即整體功能是通過元件的方式拼裝完成。

另外每個元件都可以被替換以保證靈活性。

2.Tomcat各元件及關係 Server和ServiceConnector聯結器 HTTP1.1SSLhttpsAJP( ApacheJServProtocol)apache私有協定,用於apache反向代理Tomcat Container  Engine引擎catalinaHost虛擬機器器基於域名分發請求Context隔離各個WEB應用每個Context的ClassLoader都是獨立 Component  Manager(管理器)logger(紀錄檔管理)loader(載入器)pipeline(管道)valve(管道中的閥) 二、Tomcatserver.xml設定詳解 server root元素:server的頂級設定主要屬性:port:執行關閉命令的埠號shutdown:關閉命令  演示shutdown的用法  #基於telent執行SHUTDOWN命令即可關閉(必須大寫)telnet127.0.0.18005SHUTDOWN  service 服務:將多個connector與一個Engine組合成一個服務,可以設定多個服務。

Connector 聯結器:用於接收指定協定下的連線並指定給唯一的Engine進行處理。

主要屬性: protocol監聽的協定,預設是http/1.1port指定伺服器端要建立的埠號minSpareThreads伺服器啟動時建立的處理請求的執行緒數maxThreads最大可以建立的處理請求的執行緒數enableLookups如果為true,則可以通過呼叫request.getRemoteHost()進行DNS查詢來得到遠端使用者端的實際主機名,若為false則不進行DNS查詢,而是返回其ip地址redirectPort指定伺服器正在處理http請求時收到了一個SSL傳輸請求後重定向的埠號acceptCount指定當所有可以使用的處理請求的執行緒數都被使用時,可以放到處理佇列中的請求數,超過這個數的請求將不予處理connectionTimeout指定超時的時間數(以毫秒為單位)SSLEnabled是否開啟sll驗證,在Https存取時需要開啟。

生成證書:keytool-genkey-v-aliastestKey-keyalgRSA-validity3650-keystoreD:\test.keystore[] 演示設定多個Connector Engine 引擎:用於處理連線的執行器,預設的引擎是catalina。

一個service中只能設定一個Engine。

主要屬性:name引擎名稱defaultHost預設host Host 虛擬機器器:基於域名匹配至指定虛擬機器器。

類似於nginx當中的server,預設的虛擬機器器是localhost.主要屬性:  演示設定多個Host Context 應用上下文:一個host下可以設定多個Context,每個Context都有其獨立的classPath。

相互隔離,以免造成ClassPath衝突。

主要屬性:  演示設定多個Context   Valve 閥門:可以理解成 的過濾器,具體設定要基於具體的Valve介面的子類。

以下即為一個存取紀錄檔的Valve 三、Tomcat部署指令碼編寫 Tomcat啟動引數說明 我們平時啟動Tomcat過程是怎麼樣的? 複製WAR包至Tomcatwebapp目錄。

執行starut.bat指令碼啟動。

啟動過程中war包會被自動解壓裝載。

但是我們在Eclipse或idea中啟動WEB專案的時候也是把War包複雜至webapps目錄解壓嗎?顯然不是,其真正做法是在Tomcat程式檔案之外建立了一個部署目錄,在一般生產環境中也是這麼做的即:Tomcat程式目錄和部署目錄分開。

我們只需要在啟動時指定CATALINA_HOME與CATALINA_BASE引數即可實現。

| 啟動引數 | 描述說明 ||:----|:----||JAVA_OPTS|jvm啟動引數,設定記憶體編碼等-Xms100m-Xmx200m-Dfile.encoding=UTF-8||JAVA_HOME|指定jdk目錄,如果未設定從java環境變數當中去找。

||CATALINA_HOME|Tomcat程式根目錄||CATALINA_BASE|應用部署目錄,預設為$CATALINA_HOME||CATALINA_OUT|應用紀錄檔輸出目錄:預設$CATALINA_BASE/log||CATALINA_TMPDIR|應用臨時目錄:預設:$CATALINA_BASE/temp| 可以編寫一個指令碼來實現自定義設定: ln-s/home/wukong/apache-tomcat-8.5.56apache-tomcat 更新啟動指令碼 #!/bin/bash  exportJAVA_OPTS="-Xms100m-Xmx200m" exportCATALINA_HOME=/home/wukong/apache-tomcat exportCATALINA_BASE="`pwd`" case$1in     start)     $CATALINA_HOME/bin/catalina.shstart         echostartsuccess!!     ;;     stop)         $CATALINA_HOME/bin/catalina.shstop         echostopsuccess!!     ;;     restart)     $CATALINA_HOME/bin/catalina.shstop         echostopsuccess!!         sleep3     $CATALINA_HOME/bin/catalina.shstart     echostartsuccess!!     ;;     version)     $CATALINA_HOME/bin/catalina.shversion     ;;     configtest)     $CATALINA_HOME/bin/catalina.shconfigtest     ;;     esac exit0 docker啟動tomcat dockerrun-id--name=test_tomcat-eJAVA_OPTS='-Xmx128m'-p8888:8080-v/usr/local/tuling-project/tomcat-test/webapps:/usr/local/tomcat/webapps-v/usr/local/tuling-project/tomcat-test/logs:/usr/local/tomcat/logs-v/usr/local/tuling-project/tomcat-test/conf:/usr/local/tomcat/conf--privileged=truetomcat:8 原始碼構建 下載地址:https://tomcat.apache.org/download-80.cgi 設定 1.解壓原始碼apache-tomcat-8.5.57-src 2.apache-tomcat-8.5.57-src目錄下新增pom檔案 4.0.0 org.apache.tomcat Tomcat8.0 Tomcat8.0 8.0 Tomcat8.0 java test java test org.apache.maven.plugins maven-compiler-plugin 2.3 UTF-8 1.8 1.8 junit junit 4.12 test org.easymock easymock 3.4 ant ant 1.7.0 wsdl4j wsdl4j 1.6.2 javax.xml jaxrpc 1.1 org.eclipse.jdt.core.compiler ecj 4.5.1 3.在apache-tomcat-8.5.57-src同級目錄新建catalina-home並保證目錄下面檔案如下 注意: 上面資料夾apache-tomcat-8.5.57-src裡面有的,就剪下過來,沒有的就新建一個,binconfwebapps應該是從apache-tomcat-8.5.57-src剪下過來的 4.idea引入專案 File->Open選擇解壓的C:\Users\wukong\Downloads\apache-tomcat-8.5.57-src\apache-tomcat-8.5.57-src 設定啟動 MainClass:org.apache.catalina.startup.BootstrapVmOptions:-Dcatalina.home=C:\Users\wukong\Downloads\apache-tomcat-8.5.57-src\apache-tomcat-8.5.57-src\catalina-home 啟動報錯 TestCookieFilter報錯找不到這個類CookieFilter 解決方法: 1.刪除:TestCookieFilter 啟動後,存取localhost:8080報錯org.apache.jasper.JasperException:java.lang.NullPointerException 解決方案: org.apache.catalina.startup.Bootstrap新增程式碼塊 { JasperInitializerinitializer=newJasperInitializer(); }  



請為這篇文章評分?