上一篇我們聊了Web服務(wù)器到應(yīng)用服務(wù)器的發(fā)展歷程瓦侮,今天以JavaEE的發(fā)展歷程為代表,聊一下應(yīng)用服務(wù)器的演變变隔。
假設(shè)我們從頭搭建一個Java的應(yīng)用服務(wù)器喘落。首先茵宪,我們得先實現(xiàn)網(wǎng)絡(luò)接入部分,我們管這一層叫網(wǎng)絡(luò)層瘦棋。JDK封裝了幾個操作系統(tǒng)的網(wǎng)絡(luò)模型稀火,可以幫助到我們。尤其是NIO包赌朋,提供了高性能的網(wǎng)絡(luò)支持凰狞。
通過網(wǎng)絡(luò)層,我們接收的數(shù)據(jù)還是字節(jié)序列沛慢。我們還需要根據(jù)支持的網(wǎng)絡(luò)協(xié)議赡若,把字節(jié)數(shù)據(jù)翻譯成應(yīng)用能理解的數(shù)據(jù)。比如Http協(xié)議团甲,我們要解析出哪些是Header數(shù)據(jù)逾冬,哪些是參數(shù)數(shù)據(jù),哪些是上傳的文件等等伐庭。我們管這一層叫協(xié)議層粉渠。
網(wǎng)絡(luò)層和協(xié)議層相互獨立,這樣我們就可以靈活的在兩個方面進行擴展圾另,比如支持Http2等其他協(xié)議霸株,再比如網(wǎng)絡(luò)層也可以支持更高效的網(wǎng)絡(luò)模型。
經(jīng)過協(xié)議層之后集乔,我們就得到了應(yīng)用可理解的協(xié)議對象信息去件。我們可以理解為Request對象。下一步就是傳遞給業(yè)務(wù)處理層扰路。作為一個服務(wù)器尤溜,我們應(yīng)該把請求傳遞給誰呢。
服務(wù)器應(yīng)該是可以同時運行多個應(yīng)用程序的汗唱,每個應(yīng)用程序可以對應(yīng)不同的域名宫莱。我們怎么來區(qū)分呢?我們得有一套接口規(guī)則來區(qū)分服務(wù)器代碼和業(yè)務(wù)代碼哩罪,這有點像CGI授霸。業(yè)務(wù)代碼怎么被服務(wù)器加載進來呢,業(yè)務(wù)代碼中哪些代碼對應(yīng)哪個請求呢际插,這都得有一個規(guī)范來描述碘耳。我們管這一層叫業(yè)務(wù)代碼層,在JavaEE中就是War包的規(guī)范框弛。
War包就是一個zip壓縮包辛辨,他通過一系列約定,定義了一個可被加載的業(yè)務(wù)代碼包瑟枫。比如web.xml文件放在哪個目錄下斗搞,class文件放在哪,jar包放在哪等等慷妙。
通過這個規(guī)范榜旦,服務(wù)器就能知道你這個業(yè)務(wù)代碼怎么加載。不同的代碼包之間是需要隔離的景殷,這個怎么來做呢溅呢。我們得讓不同的War文件可以加載到不同的命名空間下,這樣才能做到互相之間的隔離猿挚。我們就需要為服務(wù)器設(shè)計單獨的Class Loader體系了咐旧。
首先,服務(wù)器的公用代碼是在父加載空間中的绩蜻,這樣可以保證各個業(yè)務(wù)包代碼可以復(fù)用服務(wù)器的公用代碼铣墨。然后,服務(wù)器為每個War包提供不同的加載器办绝,這樣就保證了不同War包之間的隔離伊约。
在一個War包中姚淆,代碼也會分為兩部分。一部分是我們自己寫的代碼屡律,一部分是引用的第三方的Jar包腌逢。為了避免第三方代碼覆蓋了我們自己的代碼,War加載器會先加載class目錄下我們自己的代碼超埋,然后再加載lib目錄下第三方的代碼搏讶。
解決了代碼的隔離和覆蓋問題,我們還得看一個請求到達后霍殴,怎么去路由處理媒惕。因為一個War包會對應(yīng)很多請求Path,到底哪個Path執(zhí)行哪段代碼来庭,我們得需要描述清楚妒蔚。Web.xml文件中就清晰的描述了這個對應(yīng)關(guān)系。
在Web.xml中月弛,我們把請求Path映射到不同的Servlet上面睛。當(dāng)這個Path的請求到達后,服務(wù)器通過網(wǎng)絡(luò)層和協(xié)議層尊搬,將請求的數(shù)據(jù)封裝成Request對象叁鉴。然后,通過域名和War包的對應(yīng)關(guān)系描述佛寿,找到對應(yīng)的War包幌墓,再通過War包里的Web.xml文件,找到對應(yīng)的Servlet冀泻,最終運行執(zhí)行常侣。
有時候,我們需要在某些Path請求達到后弹渔,在Servlet處理之前做一些攔截處理胳施,這就是Filter的概念。同樣在Web.xml中肢专,我們描述了各種Filter和Path的對應(yīng)關(guān)系舞肆。
總結(jié)一下,我們把應(yīng)用服務(wù)器分拆為網(wǎng)絡(luò)層博杖、協(xié)議層椿胯、業(yè)務(wù)代碼層,逐層來簡化服務(wù)器的設(shè)計剃根,讓服務(wù)器獨立出來哩盲,開發(fā)者可以自由的編寫自己的業(yè)務(wù)邏輯。