Tomcat,熟悉的陌生人。咱們全部的項目都運行在它上面,而咱們卻每每對它視而不見。現實中也是如此,咱們周圍充滿了空氣,咱們無時無刻不在呼吸,但你歷來沒關心過它。一樣的,Tomcat於咱們而言,也只是在建立環境或者運行項目爆出各類錯誤時,纔會去看看它。html
上世紀90年代在大洋彼岸,有一家名喚SUN的公司,創造了一門全新的語言,叫Java。通過短短几年的發展,一躍成爲市場上最煊赫一時的語言。隨後又悟出「Java13絕技」,也就是所謂的JavaEE規範:JDBC,JNDI,EJB,RMI,JSP,Servlets,XML,JMS,Java IDL,JTS,JTA,JavaMail,JAF。程序員
在大洋彼岸還有一家公司,準確來講它是一個組織,專門搞開源的,叫Apache。這家公司搞出了一個叫Tomcat的服務器。這個名字取得真好啊。中國有個詞叫三腳貓,專門來吐槽別人功夫不到家。巧了,Tomcat也沒徹底實現JavaEE規範。13種核心技術,Tomcat只實現了倆:Servlet和JSP。而其餘服務器好比JBoss、Weblogic啥的都是徹底支持的。因此人們每每更願意叫Tomcat爲輕量級的服務器,也有叫它Servlet/JSP容器的。web
聽到這,你不由大叫:不對啊,我記得本身寫的程序裏有用到JDBC啊,還能夠運行哩!數據庫
啊,那是由於你導了JDBC包...可是你安裝了Tomcat後另外導過Servlet/JSP的包嗎?沒有嘛!人家實現了Servlet/JSP規範,都整到本身源碼裏了。編程
說到這,我也是淚流滿面。由於我才發現本身也是個三腳貓。上面「Java13絕技」我特麼也就學過JDBC/XML/JSP/Servlet...因此我更願意稱本身是JavaWeb程序員,而不是JavaEE程序員。JavaEE其實很重,我拿不動,打擾了。瀏覽器
在我看來,服務器最本質的做用有兩個:服務器
假設如今有個問題:微信
給你兩臺電腦,不經過藍牙/QQ/微信,也不經過網盤或USB等可移動設備作中介,你要如何把一張圖片從一臺電腦傳到另外一臺?
聽到這個問題,我估計大部分非科班的朋友都要懵。由於若是後期沒有刻意去學習計算機網絡,咱們對於網絡的瞭解基本僅限於基礎班4小時的「網絡編程」講解。而你們平時又太習慣地址欄鍵入"www.baidu.com",無腦一回車就上網衝浪了。如今忽然讓你去訪問隔壁的電腦,確實有點一籌莫展。網絡
解決這個問題的方法可能有多種,這裏介紹其中一種:經過服務器訪問。架構
請先了解如下三個概念:
中國有14億人口,每一個人都有惟一的身份標識:身份證,用以精肯定位某個個體。一樣的,網絡上有幾十億臺電腦,每臺電腦都有本身的一串特有IP(不一樣局域網內能夠相同),也就是說一個IP表明一臺特定的實體電腦。好比《唐伯虎點秋香》中華安的編號是9527,而華府的管家從不叫他名字,而是直接喊「9527」。由於「9527」就是華安。
雖然根據IP能夠精準定位一臺電腦,可是還不足以讓咱們訪問這臺電腦。就比如你知道了個人門牌號,可是我沒給你開門。所謂的門,就是一個端口,而端口的背後是應用程序。
通常來講,一個端口能夠定位一個軟件,但一個軟件能夠佔用多個端口(你家的門,只屬於你家,但能夠有先後門)。在現實生活中,你家的門若是被別人佔用了或者堵了,客人(請求)就進不去了。而在程序中,若是有兩個程序的端口相同,就會發生端口衝突,也就是所謂的「端口占用」。端口占用的後果每每是程序沒法啓動,更遑論運行。
關於端口,再舉個例子:
微信和QQ都是騰訊公司的,你的電腦上同時裝了這兩個軟件。爲何我用QQ給你發消息,你的微信收不到?正常人看起來很傻的問題,實際上並非那麼簡單。
每一個應用程序都有本身的端口號(可能有多個),它們一旦運行,就要去監聽這些端口。每一個程序都是電腦的囚犯,看不到外面的世界,而端口就是給這些囚犯送飯的窗口。應用程序們成天躲在電腦裏盯着本身的端口們,祈求着別的計算機來訪時能送個大雞腿(Request請求)。
其實QQ這些軟件屬於C/S架構,已經爲咱們屏蔽了太多底層,什麼IP、端口所有都是自動封裝的。相比來講,B/S架構更直觀一些。好比用瀏覽器訪問百度:
想要訪問一臺服務器,必須知道它的IP。但咱們人類不擅長記憶長串數字,因而人類搞了所謂的域名來指向IP。但實際請求時,最終仍是要換算成IP去訪問。總得來講有兩種換算的途徑:1.本機的hosts文件 2.DNS服務器
不知道有沒有細心的朋友注意到了下面的細節:
即便DNS解析域名獲得對應的IP後,Request請求裏仍是會帶上host。爲何?
由於:域名!=IP。
實際上一個IP能夠對應多個域名。也就是說一臺實體服務器(大鐵櫃),理論上能夠有多個域名(虛擬主機)。實體服務器和網站是兩個概念。IP只是對應實體服務器,而域名對應具體的網站。
好比上面百度服務器,雖然看起來115.239.210.27這個IP徹底等同於http://www.baidu.com,但也有可能這個IP對應的服務器上配置了兩個虛擬主機:www.baidu.com和tieba.baidu.com。因此即便找到了IP對應的服務器實體,Request請求仍是要帶上host主機名,以肯定是哪一個虛擬主機。
經過DNS解析域名獲得IP,而後根據IP+host找到服務器
另外,若是兩個域名對應同一個IP,那麼必須設置其中一個域名爲默認的,否則同一臺服務器有兩個虛擬主機,我該訪問誰?
已經知道IP,就無需DNS解析,可直接訪問服務器。若這個IP對應的服務器有兩個虛擬主機,而用戶Request請求行中又沒有指定host,則會訪問默認主機(所以服務器要事先指定默認主機!Tomcat默認localhost)
最後,再用Tomcat舉個例子。好比,如今我有一臺筆記本電腦(一個實體服務器),它的本機IP是192.168.112.1,我在上面裝了Tomcat。若是Tomcat不改動配置,則默認只有一個虛擬主機localhost(默認主機)。接着我開發了一個JavaWeb程序demo1部署到Tomcat,而後我同事在瀏覽器輸入下方地址
192.168.112.1:8080/demo1/index.html
訪問個人電腦。雖然沒有帶host,可是localhost是默認的,因而訪問它。
最後必須解釋的是,上面的百度服務器只是舉個例子,實際上百度搜索和百度貼吧的IP是不一樣的,也就是說它們不在同一臺服務器上。一般來講,一個IP對應一臺服務器,服務器上只有一個主機。拿到IP基本就能夠肯定要訪問哪一個網站。
咱們常常開口閉口「服務器」、「服務器」的,其實「服務器」是個很容易引起歧義的概念,我能想到的就有3點:
軟件概念上,只要是一臺硬件配置正常、裝有操做系統、插着電能上網,而且安裝特定軟件的電腦,均可以稱爲服務器。好比你要學習數據庫了,因而你裝了MySQL服務端,那麼此時你的電腦就是一個MySQL服務器。而後你又裝了SVN服務端,那麼此時你的電腦既是MySQL服務器,又是SVN服務器。Tomcat服務器同理。
硬件概念上,服務器本質上也是一臺電腦,只不過配置高的同時長相醜了點,基本就是一個冰冷的大鐵櫃。咱們的筆記本電腦既能看片又能玩遊戲,而它們基本上專機專用。
其實,Tomcat服務器 = Web服務器 + Servlet/JSP容器(Web容器)。
Web服務器的做用是接收客戶端的請求,給客戶端做出響應。可是很明顯,服務器不止靜態資源呀,因此客戶端發起請求後,若是是動態資源,Web服務器不可能直接把它響應回去(好比JSP),由於瀏覽器只認識靜態資源。因此對於JavaWeb程序而言,還須要JSP/Servlet容器,JSP/Servlet容器的基本功能是把動態資源轉換成靜態資源。咱們JavaWeb工程師須要使用Web服務器和JSP/Servlet容器,而一般這二者會集於一身,好比Tomcat。
Web服務器接收、響應客戶端請求,Web容器裝載Servlet/JSP,讓它們去處理動態資源[來自尚硅谷]
因此剛纔咱們畫的百度服務器,其實細節還能夠更豐滿些:
百度服務器細節圖
訪問百度完整的流程
咱們寫代碼的時候,都知道相同代碼最好抽取成公共方法以複用。如今咱們來想想,上百上千的Web應用有什麼共性嗎?首先,資源確定不一樣,沒法抽取。好比優酷主打視頻,知乎基本都是文字。其次,業務也確定不一樣,好比百度主要是搜索,淘寶是電商。可是有一點是同樣的,這些網站都須要「接收用戶請求」+「響應用戶請求」。
嗯?橋多麻袋!!這兩個概念,好像哪裏見過!不錯,就是上面的Web服務器。仔細回想一下,咱們開發JavaWeb時,你操心過如何接收HTTP請求和響應HTTP請求嗎?顯然沒有嘛!由於你一直忙着debug。
因此,咱們用Java開發的Web應用只是一個半成品,相似於一個插件,而服務器則像一個收發器:
其實對於何謂動態資源,我也沒有很精準的概念。要講清楚一個東西是什麼,有時是比較難的事。不如先說它不是什麼。
首先,動態資源不等同於動態頁面。所謂動態頁面,就是頁面會動,而會動的頁面不必定是動態資源。好比我能夠用JQuery執行一段代碼,讓一個Div不斷放大縮小,可是很顯然它仍是一個HTML頁面。
所謂動態資源,其實最顯著的特徵就是它能動態地生成HTML!好比JSP。動態資源有個「特點」:它的數據是「可拼裝」的、並且「能夠隨時間變化」。下面用號稱能夠抗住8個明星同時出軌的新浪服務器舉個例子:
忽然,新浪《花花世界》專欄的小編髮現,原來和bravo1988有緋聞的不是劉亦菲,而是佟麗婭,因而打開專欄作了修改:
此時,粉絲們再次打開《花花世界》專欄,看到的就是:佟麗婭深夜買醉bravo。
上面這個例子很好地說明了動態資源(JSP)的兩個特性:
那麼爲何說HTML就是靜態資源呢?我也能夠修改HTML頁面使它發生改變啊!很好,頗有想法。那麼請小編先學會Linux,而後遠程鏈接服務器進入到Tomcat目錄下修改吧。
動態資源和靜態資源雖然都在服務器裏,可是動態資源包含變量(「可拼裝」特性),而變量維繫着數據庫和程序之間的聯繫。
若是把JSP比做電子廣告牌,變量比做一根電線,而電線鏈接着一臺電腦(數據庫服務器)。那麼只要電腦上從新編輯文本,廣告牌的內容也會變,此謂動態。而靜態資源就像一張佈告,當初寫什麼就是什麼,任他風吹雨打,都不會再改變了。
Tomcat的目錄結構就再也不多說,每一個機構的培訓視頻都會強調。
先看一下個人Tomcat目錄(免安裝版),我把它放在了F盤的develop文件夾下:
重點介紹一下Tomcat的架構:
嗯?這個connector的畫法,好像哪裏見過?
其實這張圖,應該結合Tomcat的一個配置文件(Server.xml)來看:
簡略解釋一下xml裏的配置:
配置介紹到這裏,要先停一下,講個故事:
從前有個國家,叫The United States of Tomcat。
國王Service是個愛貓的人,家庭和諧美滿。他立了一個太子,叫作Engine。
另外還有還幾個很小的兒子,不過都是親王(Connector),將來可能還要再生幾個Connector。
因爲Tomcat國實在過小了,全城上下就幾我的,因此親王Connector們被派去守城門。
爲了讓太子獲得鍛鍊,早日繼承衣鉢,國王Service告訴親王兒子們:他國使者若來拜訪,大家就帶他去大家哥哥Engine那去,他會處理一切。
Engine貴爲太子,有好幾處府邸,好比HOST1,HOST2,將來可能再建幾座府邸(新建虛擬主機),可是Engine說了,我通常都在localhost待着,來這找我即可。
每一座府邸裏,都有好幾個廂房(Context:咱們開發的Web應用)。Engine會根據來訪使者的通關文牒(localhost:8080/myWeb/index.html)安排他們去哪一個房間(myWeb),拿什麼禮品(index.html)。
最後結合文件目錄再看一次Tomcat架構:
有兩個Servlet很重要,可是在「淺談JSP」中沒有提到。
TestDefaultServlet
上面案例中,我新建一個動態web工程,只是寫了一個HTML,沒有編寫Servlet,甚至一句Java代碼都沒寫。可是啓動Tomcat後我卻能夠經過瀏覽器訪問到剛纔編寫的haha.html。這是爲什麼?
咱們知道,對於像Tomcat這樣的Servlet容器來講,任何一個請求的背後確定有個Servlet在默默處理:
因此此次也不例外,確定也有對應的Servlet處理了本次請求。既然不是咱們寫的,那隻能是Tomcat提供的。查看Tomcat下的conf目錄,除了咱們熟悉的Server.xml,還有個web.xml。
不錯,咱們每一個動態web工程都有個web.xml,而conf裏的這個,是它們的「老爹」。它裏面的配置,若是動態web工程沒有覆蓋,就會被「繼承」下來。咱們會發現,conf/web.xml裏配置了一個DefaultServlet:
DefaultServlet的做用:最低級匹配,當沒有對應的Servlet處理當前請求時,才輪到它處理。要麼找到並響應請求的資源,要麼給出404頁面。
咱們都知道JSP是「化了濃妝」的Servlet,可是好不容易假裝成了一個JSP,是誰幫它卸妝的呢?另外,你們仔細想一想,通常來講JavaWeb階段咱們訪問資源有三種「形式」:
localhost:8080/demo/AServlet:很明顯,咱們手動寫了一個AServlet處理它 localhost:8080/demo/haha.html:雖然咱們沒寫,可是Tomcat本身準備了DefaultServlet localhost:8080/demo/index.jsp:我擦,誰來處理?
對呀,細思恐極,這*.jsp的資源,誰來處理?其實就是JspServlet。它的做用簡而言之就是:
剛纔帶你們看conf/web.xml時,我把它隱藏了,由於同時講解DefaultServlet和JspServlet會比較亂。強烈建議你們如今暫停一下,打開本機的Tomcat找到conf/web.xml看一下。下面是JspServlet的配置:
因此最後總結一下Tomcat處理請求的幾種方式:
最後,還有個很無聊的問題留給你們思考:JavaSE階段,咱們不管作什麼,都是上來先敲main()。學了JavaWeb後,我想問問,你有多久沒敲main()了?她去哪了呢?
動手實現Tomcat(黑馬公開課):連接見評論區置頂。