在日常調試項目時,總是利用tomcat去啟動項目,並進行前后端聯調,但對於前后端的請求響應的交互原理及過程並不是特別清晰。
為什么在前端發出相應請求,就能跳轉到后端通過程序得到結果再響應到前端頁面呢?!
為了加深對該過程的理解,故以tomcat為例,撰寫此文。
一、Tomcat部分
Tomcat總體結構:
Server->Service->Connector&Container(Engine->Host->Context(Wrapper(Servlet)))

如圖所示的Ttomcat結構圖,其核心是Connector和Container組件,其中Connector組件可以被替換從而提供更多選擇,因此一個Container可以選擇對應多個Connector。
Server
多個Connector和一個Container就形成了一個Service,就有了對外提供服務的能力。而光有Service還不行,還必須給其一個生存環境去發揮去作用,這項生殺大權的掌握者就花落Server手中了。
因此,Tomcat的生命周期就由Server來控制。
Server的作用很簡單,就是對外提供接口讓其他程序能夠訪問到其中的Service集合,同時維護包含的所有Service的生命周期,如初始化、找到對應service和結束服務等。
Service
對於Service來說,主要是對外提供服務,其中的Connector主要是負責對外交流,而Container則是處理內部事務。一個Service可有多個Connector,但只能有一個Container。

Connector
對於Connector來說,它將在某個指定的端口上來監聽客戶請求,把從socket傳遞過來的數據封裝成Request,傳遞給Engine來進行處理,並從Engine處獲得響應並返回給客戶。Tomcat通常會用到兩種Connector:Http Connector,在端口8080處監聽來自客戶browser的http請求;AJP Connector,在端口8009處監聽來自其他webServer的Servlet/jsp代理請求。
Container
在Container核心組件中,包含了以下幾個核心部分:Wrapper、Host、Engine、Context。

其中Engine是負責處理所有相關聯的service請求,並將結果返回給service。而Connector則是作為service和engine之間的橋梁。一個engine下可以配置一個默認主機,每個虛擬主機都有一個域名。當engine接收到一個請求時,它會將該請求匹配到虛擬主機(host)上,然后將請求交給host來處理。若無法匹配到虛擬主機,則將其交給默認host來處理,以線程方式來啟動host。
Host代表一個虛擬主機,每個虛擬主機和某網絡域名相匹配。每個虛擬主機下可以有一個或多個web應用,每個web應用對應於一個context,相對應有contextpath。當主機接收到請求時,會將該請求匹配到某個context上,然后把請求交給該context來處理。
一個Context對應於一個web應用。一個web應用由一個或多個servlet組成。context在創建時將根據配置文件$ CATALINA_HOME/conf/web.xml和$ WEBAPP_HOME/WEB-INF/web.xml載入Servlet類。當Context獲得請求時,將在自己的映射表(mapping table)中尋找相匹配的Servlet類,如果找到,則執行該類,獲得請求的回應,並返回。
Wrapper代表了一個Servlet,負責管理Servlet的裝載、初始化、執行以及資源回收。wrapper的實現類是StandardWrapper,該類還實現了擁有一個Servlet初始化信息的ServletConfig。
Lifecycle:在編程中也有很多對象是具有生命周期的,從初始化、運行、回收等 會經歷幾個不同的階段。 在tomcat中容器相關的好多組建都實現了Lifecycle接口,當tomcat啟動時,其依賴的下層組件會全部進行初始化。 並且可以對每個組件生命周期中的事件添加監聽器。例如當服務器啟動的時候,tomcat需要去調用servlet的init方法和初始化容器等一系列操作,而停止的時候,也需要調用servlet的destory方法。而這些都是通過org.apache.catalina.Lifecycle接口來實現的。由這個類來制定各個組件生命周期的規范。
Tomcat-Servlet的過程:
1、Tomcat在啟動時,會加載server;

2、Server啟動時,會加載Service;

3、Service中會加載Container;

4、Container中的Wrapper含有Servlet;

5、在HttpServlet中含有一些doGet、doPost、service等方法,用來處理各種類型的請求。

Tomcat Server處理一個http請求的過程:
假設來自客戶的請求為:
http://localhost:8080/test/index.jsp
1) 請求被發送到本機端口8080,被在那里偵聽的Coyote HTTP/1.1 Connector獲得
2) Connector把該請求交給它所在的Service的Engine來處理,並等待來自Engine的回應
3) Engine獲得請求localhost/test/index.jsp,匹配它所擁有的所有虛擬主機Host
4) Engine匹配到名為localhost的Host(即使匹配不到也把請求交給該Host處理,因為該Host被定義為該Engine的默認主機)
5) localhost Host獲得請求/test/index.jsp,匹配它所擁有的所有Context
6) Host匹配到路徑為/test的Context(如果匹配不到就把該請求交給路徑名為""的Context去處理)
7) path="/test"的Context獲得請求/index.jsp,在它的mapping table中尋找對應的servlet
8) Context匹配到URL PATTERN為*.jsp的servlet,對應於JspServlet類
9) 構造HttpServletRequest對象和HttpServletResponse對象,作為參數調用JspServlet的doGet或doPost方法
10)Context把執行完了之后的HttpServletResponse對象返回給Host
11)Host把HttpServletResponse對象返回給Engine
12)Engine把HttpServletResponse對象返回給Connector
13)Connector把HttpServletResponse對象返回給客戶browser
二、Serlvet原理
從Tomcat部分我們可以看出,browser的請求在層層傳遞下最終在Servlet處進行請求的處理及響應。因此本部分主要圍繞傳遞過來的請求和響應部分來進行闡述。
1、認知Servlet
作為Javaweb三大組件(Servlet,Filter,Listener)之一的Servlet,每一個都是唯一的,所能處理的請求是不同的。
Servlet是一種獨立於平台和協議的服務器端的java應用程序,運行於java服務器中,可以動態擴展服務器能力,並采用請求-響應模式來提供web服務。
Servlet是一個單實例多線程的。只能被實例化一次,而每次service服務會開啟新線程進行處理新請求。
2、Servlet生命周期
前面說到,在Tomcat核心組件Container中,一個web應用由一個或多個Servlet組成,而一個Context對應一個web應用,在創建時會去根據配置文件$ CATALINA_HOME/conf/web.xml和$ WEBAPP_HOME/WEB-INF/web.xml載入Servlet類。
因此Servlet的生命周期由web容器來負責,根據web.xml來加載對應的Servlet類。Servlet核心代碼如下:

在上圖所示的五個方法中,其中init、service和destroy三個方法均為生命周期方法,在第一次被訪問時出生,在關閉服務器時死亡。
init方法會在Servlet對象創建之后馬上執行,且只執行一次。
destroy方法會在Servlet被銷毀之前調用,也只執行一次。
對於service方法,則可以被多次調用,每次處理請求時都是在調用該方法。
getServletConfig可以獲得Servlet的配置信息。
getServletInfo方法可以獲得Servlet信息。

從Servlet.class文件中我們可以看到,與之相關聯的由ServletConfig、ServletRequest、ServletResponse三個類,這三個類都是通過web容器傳遞給Servlet的。
其中,ServletConfig是在Servlet初始化時就通過web.xml文件解析傳給了Servlet,后兩個都是請求到達時調用Servlet.service時才傳遞過來的。

在第一部分講解Wrapper時也說過,它代表了一個Servlet。通過查詢源碼發現,StandardWrapper和StandardWrapperFacede都實現了ServletConfig接口,而 StandardWrapperFacade 是 StandardWrapper 門面類(門面設計模式)。所以傳給 Servlet 的是 StandardWrapperFacade 對象,這個類能夠保證從 StandardWrapper 中拿到 ServletConfig 所規定的數據,而又不把 ServletConfig 不關心的數據暴露給 Servlet。
3、Servlet工作過程
1)browser發出一個http請求;
2)Tomcat的Connector組件監聽到該請求,其主線程會創建HttpServletRequest對象和HTTPServletResponse對象;
3)從請求URL中找到正確Servlet后,Tomcat為其創建或分配一個線程,同時將2中對象傳遞給該線程;
4)Tomcat調用Servlet的service()方法,會根據請求參數的不同來調用doGet()或doPost()等方法,並將結果返回到HTTPServletResponse對象中;
5)Tomcat將響應結果返回到browser。
三、HTTP與服務器的交互方式
1、http簡介
HTTP協議,即超文本傳輸協議,基於TCP/IP通信協議來傳輸數據,工作於客戶端-服務端架構上,通過URL向Web服務器(Apache服務器等)傳輸請求並得到響應。默認端口為80,也可以設置為8080等。
HTTP三點注意事項:
HTTP是無連接:無連接的含義是限制每次連接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答后,即斷開連接。采用這種方式可以節省傳輸時間。
HTTP是媒體獨立的:這意味着,只要客戶端和服務器知道如何處理的數據內容,任何類型的數據都可以通過HTTP發送。客戶端以及服務器指定使用適合的MIME-type內容類型。
HTTP是無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味着如果后續處理需要前面的信息,則它必須重傳,這樣可能導致每次連接傳送的數據量增大。另一方面,在服務器不需要先前信息時它的應答就較快。
2、http消息結構
客戶端發送一個HTTP請求到服務器的請求消息包括以下格式:請求行(request line)、請求頭部(header)、空行和請求數據四個部分組成,
下圖給出了請求報文的一般格式。

HTTP響應也由四個部分組成,分別是:狀態行、消息報頭、空行和響應正文。

3、請求方式
HTTP1.0有三種:get、post、head;
HTTP1.1新增了五種:options、put、delete、trace和connect。

其中較為常用的為get、post、delete和put,這大致對應着對該資源的查、改、刪、增四個操作。
1)Get請求用於向服務器進行信息獲取,是安全和冪等的。它僅僅是為了獲取信息,不會影響資源的狀態;所謂冪等,即對於同一個URL的多個請求返回的結果都一致。
get請求會將數據附在URL之后,以?來進行分割,參數之間以&來進行連接。對於非英文字母/數字等,都需要進行格式的轉換。而由於其在URL進行拼接,對於涉及到密碼等請求,是不安全的。
在HTTP協議中對URL長度並沒有作出限制,而URL的最大長度其實和用戶瀏覽器以及web服務器有關。如IE為2048,Google為8182,Apache(Server)為8192。
2)Post請求表示向服務器提交數據的一種請求,可能修改服務器上的資源,類似數據庫的insert一樣。post對於數據的提交是放置在http包的包體當中的。理論上post請求是沒有大小限制的,起限制作用的是服務器處理程序的處理能力。如IIS 6.0默認post數據最大為200KB,每個表單限制為100KB。post 的安全性比get高。
3)Put請求也是向服務端發送數據從而改變信息,類似於數據庫的update一般。
4)Delete請求就是刪除某一資源的,類似於數據庫的delete操作。
四、SpringMVC下前后端交互過程

1、交互過程
由於目前接觸的項目是建立在springMVC模式下的,故根據上圖所示,在最后對SpringMVC下的請求響應過程進行解析:
1)用戶發送一個URL請求到前端控制器DispatcherServlet;
2)前端控制器將請求發給處理器映射器HandlerMapping,它會根據xml配置、注解等進行查找hander;
3)處理器映射器返回執行鏈HandlerExecutionChain(里面有handler對象,在它之前有多個interceptor攔截器);
4)前端控制器通過處理器適配器HandlerAdapter去執行Handler,不同的Handler由不同的適配器執行;
5)通過Handler處理器,即我們熟悉的Controller來處理業務邏輯;
6)處理完之后,返回ModelAndView對象,其中有視圖名稱,模型數據等;
7)HandlerAdapter將ModelAndView返回給DispatcherServlet;
8)DispatcherServlet將得到的ModelAndView傳遞給視圖解析器ViewResolver進行解析;
9)ViewResolver解析后返回具體的視圖View;
10)前端控制器對視圖View和數據進行渲染,將模型數據等填充到request域中;
11)將最終的視圖返回給客戶,產生response響應。
2、組件名詞解釋
前端控制器DispatcherServlet:接收請求響應結果,相當於轉發器、中央處理器,減少了其他組件之間的耦合度;
處理器映射器HandlerMapping:根據請求URL查找handler;
處理器適配器HandlerAdapter:按特定規則去執行handler,故編寫handler時按HandlerAdapter要求去做,這樣適配器才可正確執行handler;
視圖解析器ViewResolver:根據邏輯視圖解析成真正的視圖(View對象)
視圖View:View是一個接口,實現類支持不同的View類型(jsp,PDF,Excel...)
因個人學識有限,若上述內容某處敘述不當,請指教!
