1.我們了解tomcat的意義
? ? 雖然現(xiàn)在Spring boot技術(shù)已經(jīng)普及,但是,Spring boot,嵌入的tomcat其原理不會(huì)有多大的改變,我們?nèi)绻肷钊肓私鈝eb項(xiàng)目,我覺得tomcat還是有必要稍微了解一下。因?yàn)?,縱然springboot再怎么妖,萬變不離其宗,而且,這么優(yōu)秀的開源項(xiàng)目,其思想很值得借鑒,這邊我稍微來說說,tomcat在加載Servlet的
過程。?
2.為什么要用servlet和servlet 容器
? ? ? 首先 再Spring boot 出來之前,我估計(jì)絕大多數(shù)web 應(yīng)用都部署在 web應(yīng)用容器上面的吧因此,就出現(xiàn)了servlet 還有web容器,這些第都是為了處理http請(qǐng)求,解析分配url。servlet容器負(fù)責(zé)處理連接,分配請(qǐng)求。servlet負(fù)責(zé)對(duì)業(yè)務(wù)邏輯進(jìn)行處理。這么設(shè)計(jì)也是為了最大的解耦,讓業(yè)務(wù)開發(fā)人員屏蔽繁瑣的連接和url的分配上解放出來,專注業(yè)務(wù)開發(fā)中去。
3.tomcat容器的分層
? ? ? TomCat 有好幾層容器 其中我們應(yīng)用是部署在Container容器->Engine容器->Host容器-Context容器下
我們的每個(gè)servlet 會(huì)被包裝在 對(duì)應(yīng)Wrapper下。我們?cè)赟ervlet的中,所說的容器其實(shí)就是Context容器。在tomcat中,我們可以認(rèn)為一個(gè)war包對(duì)應(yīng)一個(gè)Context容器(我猜想,當(dāng)初tomcat的設(shè)計(jì)者沒有想到,我們的互聯(lián)網(wǎng)的體量會(huì)變得這么大,只是想的在一個(gè)節(jié)點(diǎn)下部署多個(gè)web應(yīng)用,用tomcat來進(jìn)行管理,不過自從我接觸java以來,就沒人這么玩過,估計(jì)是覺得,對(duì)維護(hù)單個(gè)項(xiàng)目太不方便了,一個(gè)項(xiàng)目要發(fā)布,其他項(xiàng)目都得停,這太不合理了。所以,我反而覺得這么設(shè)計(jì)有點(diǎn)重!至于為啥,我得在研究研究了)至于servlet對(duì)象會(huì)被包裝成Wrapper對(duì)象,而不是Servlet對(duì)象,就是為了解耦吧,warpper是屬于tomcat的,它起到代Servlet的作用,這是我個(gè)人看法。我們市面上其實(shí)有很多的servlet容器,但是無論哪種servlet容器,都可以加載,運(yùn)行我們的servlet代碼,我覺得都是通過類似tomcat的方案來進(jìn)行解耦。越學(xué)習(xí),越會(huì)發(fā)現(xiàn)那些優(yōu)秀項(xiàng)目設(shè)計(jì)者的思想值得學(xué)習(xí)!
4.tomcat容器啟動(dòng)的過程
? ? ? 我們 tomCat 在啟動(dòng)的過程中,先分別啟動(dòng)Container容器->Engine容器->Host容器->Context容器。Context容器啟動(dòng)的過程中會(huì)加載web.xml文件,解析好的配置信息,會(huì)存放到WebXml 對(duì)象中(很像spring中的BeanDefinition),加載完成以后,再把WebXml 對(duì)象解析到Context容器中去。我們配置的servlet,filter等組件,都再WebXml對(duì)象中,Context容器會(huì)根據(jù)WebXml的對(duì)象信息,會(huì)將我們配置的Servlet,加載到StandradWarpper對(duì)象中,在這對(duì)象中,里面有對(duì)Servlet描述。不得不說這又和Spring bean 從applicationContext.xml文件中加載到Spring容器中的bean很像。這里再度表達(dá)一下這種設(shè)計(jì)思想實(shí)在是太偉大了。
5.Servlet加載過程
? ? ? 接下來,在加載完配置以后,如果這個(gè)時(shí)候,我們?cè)趙eb.xml 中如果配置了 load-on-startup為1以后,我們?nèi)萜鲿?huì)加載servlet了,其實(shí)就是StandradWarpper通過反射工廠,來創(chuàng)建servlet實(shí)例化對(duì)象,然后執(zhí)行我們寫的init方法。這讓我想起spring bean在實(shí)例化的過程中,通過反射實(shí)例化,調(diào)用bean的init方法,這樣servlet就被加載起來了。
6.談下我們?nèi)粘m?xiàng)目啟動(dòng)過程
? ? ? 以上述過程中,我們可以來看下,我們傳統(tǒng)非spring boot tomcat的啟動(dòng)過程。首先調(diào)用tomcat的startup方法。tomcat監(jiān)聽端口,啟動(dòng)各容器。啟動(dòng)容器過程中,加載web.xml配置。通常springMVC中會(huì)在web.xml文件中配置DispatcherServlet,默認(rèn)都是容器啟動(dòng)。所以,在Context容器初始化完成以后,就會(huì)加載DispatcherServlet。而在初始化,執(zhí)行servlet init方法的時(shí)候,就會(huì)初始化spring 容器,最終將spring 容器存放到ServletContext中,這樣我們項(xiàng)目就通過tomcat可以被外部訪問了。