一、Web運(yùn)作原理探析
==Key:理解Web的概念及其運(yùn)作原理。==
1.1、Web概念與特征
1990年,互聯(lián)網(wǎng)之父Berners-Lee在自己編寫的圖形化Web瀏覽器"WorldWideWeb"上成功的訪問(wèn)了第一個(gè)名為"nxoc01.cern.ch"的Web服務(wù)器。經(jīng)過(guò)幾十年的發(fā)展,如今,Web是網(wǎng)絡(luò)上使用最廣泛的分布式應(yīng)用架構(gòu),它旨在共享分布在網(wǎng)絡(luò)上的各個(gè)Web服務(wù)器中的所有互相鏈接的信息。
Web使用HTML超級(jí)文本技術(shù)鏈接網(wǎng)絡(luò)上的信息,采用客戶/服務(wù)器通信模式,客戶與服務(wù)器之間用HTTP超文本傳輸協(xié)議通信。==歸納其特征為以下三點(diǎn)==:
- 使用HTML超級(jí)文本技術(shù)表達(dá)信息、建立信息與信息的鏈接
- 采用統(tǒng)一資源定位符URL精確定位網(wǎng)絡(luò)資源。URL是專為標(biāo)識(shí)網(wǎng)絡(luò)上的資源位置而設(shè)計(jì)的編制格式(編址格式:應(yīng)用層協(xié)議+IP地址/域名+資源路徑)
- 服務(wù)器與用戶代理之間的數(shù)據(jù)交換遵循HTTP協(xié)議
1.2、HTTP協(xié)議簡(jiǎn)介
==Web的核心是HTTP協(xié)議,Web的客戶端和服務(wù)器能夠交流的前提是遵循HTTP協(xié)議。HTTP協(xié)議是應(yīng)用層協(xié)議,建立在TCP/IP基礎(chǔ)之上,其規(guī)定了Web的基本運(yùn)作過(guò)程,以及用戶代理與Web服務(wù)器之間的通信細(xì)節(jié)。==
HTTP協(xié)議規(guī)定的信息交換過(guò)程如下:

當(dāng)用戶輸入一個(gè)URL地址時(shí),用戶代理會(huì)生成一個(gè)HTTP請(qǐng)求,建立與遠(yuǎn)程HTTP服務(wù)器的TCP連接,然后把HTTP請(qǐng)求發(fā)送給遠(yuǎn)程HTTP服務(wù)器,HTTP服務(wù)器再返回包含響應(yīng)網(wǎng)頁(yè)數(shù)據(jù)的HTTP響應(yīng),用戶代理接收到這個(gè)響應(yīng)后進(jìn)行展示。當(dāng)用戶代理與服務(wù)器數(shù)據(jù)交換完畢,就會(huì)斷開(kāi)連接。
==HTTP的請(qǐng)求格式和響應(yīng)格式==
HTTP協(xié)議規(guī)定,HTTP的請(qǐng)求由3部分構(gòu)成,分別是:
- 請(qǐng)求方法、URI和客戶端HTTP協(xié)議版本
- 請(qǐng)求頭,包含許多有關(guān)客戶端環(huán)境和請(qǐng)求正文的有用信息,如聲明瀏覽器的類型,請(qǐng)求正文的類型和長(zhǎng)度等
- 請(qǐng)求正文,協(xié)議規(guī)定請(qǐng)求頭與請(qǐng)求正文之間必須以空行分隔,該空行表示請(qǐng)求頭部分已結(jié)束
HTTP響應(yīng)也由3部分構(gòu)成,分別是:
- 服務(wù)器端HTTP協(xié)議的版本,狀態(tài)碼和描述
- 響應(yīng)頭,同請(qǐng)求頭,響應(yīng)頭包含服務(wù)器類型,正文類型和長(zhǎng)度等有用信息
- 響應(yīng)正文
二、Tomcat簡(jiǎn)介
==Key:Tomcat作為Web容器的基本功能==
2.1、Web服務(wù)器和Servlet
在介紹Tomcat之前,建議先讀這篇文章梳理清楚Web應(yīng)用,Web服務(wù)器和Tomcat的關(guān)系,有助于理解Tomcat的由來(lái)和所扮演的角色:
原文鏈接:https://www.cnblogs.com/vipyoumay/archive/2017/08/31/7455431.html
《一文看懂web服務(wù)器、應(yīng)用服務(wù)器、web容器、反向代理服務(wù)器區(qū)別與聯(lián)系》
==閱讀上文可知,隨著Web服務(wù)器朝著企業(yè)級(jí)應(yīng)用方向發(fā)展,一些Web程序開(kāi)發(fā)框架橫空出世(如Tomcat),它們不解決具體的業(yè)務(wù)問(wèn)題,只關(guān)注Web開(kāi)發(fā)過(guò)程中的通用邏輯,如應(yīng)用的快速部署、統(tǒng)一配置,通信、安全性和性能問(wèn)題等。而業(yè)務(wù)邏輯則由應(yīng)用軟件開(kāi)發(fā)商實(shí)現(xiàn)。開(kāi)發(fā)人員只需將應(yīng)用發(fā)布到Web服務(wù)器上運(yùn)行即可。==
可是Web應(yīng)用和Web服務(wù)器作為兩個(gè)不同的軟件系統(tǒng),它們之間如何進(jìn)行協(xié)作?遵循中介方制定的標(biāo)準(zhǔn)接口是方案的一種。SUN公司作為Java語(yǔ)言的創(chuàng)建者,制定了Web應(yīng)用和Web服務(wù)器進(jìn)行協(xié)作的一系列標(biāo)準(zhǔn)Java接口(統(tǒng)稱Java Servlet API),對(duì)Web服務(wù)器發(fā)布及運(yùn)行Web應(yīng)用的細(xì)節(jié)作了規(guī)約,它們統(tǒng)稱為Servlet規(guī)范。
中介方規(guī)定:
- Web服務(wù)器可以訪問(wèn)任意一個(gè)Web應(yīng)用中實(shí)現(xiàn)Servlet接口的類
- Web應(yīng)用中用于被Web服務(wù)器動(dòng)態(tài)調(diào)用的程序代碼位于Servlet接口的實(shí)現(xiàn)類中
Servlet最常見(jiàn)的用途是擴(kuò)展Web服務(wù)器的功能。它完全由Java編寫,運(yùn)行在服務(wù)器端,可被服務(wù)器動(dòng)態(tài)加載并執(zhí)行。
==因Web應(yīng)用發(fā)布和運(yùn)行在Web服務(wù)器中,因此我們將遵循Servlet規(guī)范的Web服務(wù)器又稱為Web容器或Servlet容器。== Tomcat就是由Apache開(kāi)源組織創(chuàng)建的優(yōu)秀的Servlet容器,想獲取更多內(nèi)容請(qǐng)移步Tomcat官網(wǎng):http://tomcat.apache.org/
2.2、Tomcat作為Servlet容器的基本功能
==簡(jiǎn)單來(lái)說(shuō),Tomcat作為運(yùn)行Servlet的容器,其基本功能是負(fù)責(zé)接收和解析來(lái)自客戶的請(qǐng)求,同時(shí)把客戶的請(qǐng)求傳送給相應(yīng)的Servlet,并把Servlet的響應(yīng)結(jié)果返回給客戶。==
Servlet規(guī)范規(guī)定的Servlet容器響應(yīng)客戶請(qǐng)求訪問(wèn)特定Servlet的流程如下:
- 用戶代理發(fā)出要求訪問(wèn)特定Servlet的請(qǐng)求
- Servlet容器接收到客戶請(qǐng)求并解析
- Servlet容器創(chuàng)建ServletRequest對(duì)象,該對(duì)象包含了客戶請(qǐng)求信息及其他關(guān)于客戶的信息
- Servlet容器創(chuàng)建ServletResponse對(duì)象
- Servlet容器將步驟3和步驟4創(chuàng)建的ServletRequest對(duì)象和ServletResponse對(duì)象作為參數(shù)傳遞給客戶所請(qǐng)求的Servlet的service()方法
- Servlet從ServletRequest對(duì)象中獲取客戶的請(qǐng)求信息
- Servlet利用ServletResponse對(duì)象生成響應(yīng)結(jié)果
- Servlet容器把Servlet生成的響應(yīng)結(jié)果發(fā)送給客戶
2.3、Tomcat必知必會(huì)及機(jī)制
Tomcat遵循Servlet規(guī)范,其響應(yīng)客戶請(qǐng)求訪問(wèn)特定Serlvet的流程在上一節(jié)中已作描述
-
Tomcat目錄結(jié)構(gòu):其目錄結(jié)構(gòu)依賴于Tomcat自身實(shí)現(xiàn),與Servlet規(guī)范無(wú)關(guān)。/conf/server.xml用于描述容器組件,常見(jiàn)的"Address already in use:bind"錯(cuò)誤可通過(guò)修改該文件配置修復(fù);/lib目錄中的jar包不僅能被Tomcat訪問(wèn),還能被所有發(fā)布在tomcat中的應(yīng)用訪問(wèn)。而javaWeb應(yīng)用中的lib子目錄只能被當(dāng)前JavaWeb應(yīng)用訪問(wèn)
Tomcat目錄結(jié)構(gòu) ==Tomcat為JavaWeb應(yīng)用加載類的加載機(jī)制:JavaWeb應(yīng)用的WEB-INF/classes目錄-->WEB-INF\lib目錄下的jar包-->Tomcat的lib目錄-->tomcat的lib目錄中的jar包。在上述所有目錄中查找未果,程序會(huì)拋出異常。==
開(kāi)發(fā)時(shí)大家可能遇到過(guò)這種情況,程序中成功引用了某個(gè)類的方法,運(yùn)行時(shí)卻報(bào)classNotFound錯(cuò)誤,原因很可能是程序引用的是Tomcat的lib目錄中jar的類,但應(yīng)用的lib下也存在一個(gè)同名的jar包,不過(guò)版本與前者不同。根據(jù)Tomcat的類加載機(jī)制,它會(huì)成功加載應(yīng)用下的jar包中的class,因版本不同該class中沒(méi)有程序中引用的方法那么就會(huì)報(bào)classNotFound錯(cuò)誤Tomcat既可以運(yùn)行采用開(kāi)放式目錄結(jié)構(gòu)的Web應(yīng)用,也可以運(yùn)行Web應(yīng)用的war文件。Tomcat服務(wù)器啟動(dòng)時(shí),會(huì)把webapps目錄下所有WAR文件自動(dòng)展開(kāi)為開(kāi)放式的目錄結(jié)構(gòu)
Web應(yīng)用的默認(rèn)URL入口是Web應(yīng)用的根目錄名
Tomcat的<Context>元素的使用可以幫助我們更靈活的發(fā)布web應(yīng)用
三、創(chuàng)建一個(gè)JavaWeb應(yīng)用
==Key:如何編寫一個(gè)Demo程序==
3.1、JavaWeb應(yīng)用的定義
先看一下JavaWeb的定義:
SUN的Servlet規(guī)范對(duì)JavaWeb應(yīng)用的定義:JavaWeb應(yīng)用由一組Servlet/JSP、HTML文件、相關(guān)Java類,以及其他可以被綁定的資源構(gòu)成,它可以在由各種供應(yīng)商提供的符合Servlet規(guī)范的Servlet容器中運(yùn)行。
3.2、JavaWeb應(yīng)用的目錄結(jié)構(gòu)
為了讓Servlet容器能順利的找到JavaWeb應(yīng)用中的各個(gè)組件,Servlet規(guī)范規(guī)定,JavaWeb應(yīng)用必須采用固定的目錄結(jié)構(gòu),每種類型的組件在Web應(yīng)用中都有固定的存放目錄。應(yīng)用的配置信息必須存放在WEB-INF/web.xml文件中,Servlet容器從該文件中讀取配置信息。
因此我們?cè)陂_(kāi)發(fā)Web應(yīng)用時(shí),需嚴(yán)格遵循上述規(guī)定。JavaWeb應(yīng)用的目錄結(jié)構(gòu)如下面的圖表所示:
如今我們?cè)陂_(kāi)發(fā)應(yīng)用程序時(shí)已經(jīng)很少親自去構(gòu)建應(yīng)用程序目錄,強(qiáng)大的IDE會(huì)將這些“雜活”處理妥當(dāng)。
3.3、照書(shū)創(chuàng)建1個(gè)JavaWeb應(yīng)用helloapp
對(duì)于helloapp應(yīng)用的構(gòu)建,只關(guān)注其組件構(gòu)成和運(yùn)行邏輯。
helloapp應(yīng)用包含如下組件:
HTML組件:login.htm,作為登陸頁(yè)面,該組件包含登錄表單,用戶提交表單后會(huì)觸發(fā)HTTP請(qǐng)求到服務(wù)器,服務(wù)器根據(jù)web.xml發(fā)布描述符中的配置信息,將請(qǐng)求映射到特定Servlet處理
Servlet組件:DispatcherServlet類,被Web容器動(dòng)態(tài)調(diào)用,它從ServletRequest對(duì)象中獲取表單數(shù)據(jù)并處理,可重定向至特定JSP,這里用到的是服務(wù)器端重定向
-
JSP組件:hello.jsp,在此案例中用于展示Servlet類的處理結(jié)果,它將作為響應(yīng)返回到客戶端并重新渲染客戶端頁(yè)面
服務(wù)器端重定向
圖示是服務(wù)器端重定向示意圖,原圖引自《Head First Servlets and JSP》,了解更多服務(wù)器端重定向和客戶端重定向知識(shí)請(qǐng)移步 https://blog.csdn.net/bluishglc/article/details/7953614 ==服務(wù)器端程序編寫完成后,需要編輯供web.xml,Servlet容器在加載和啟動(dòng)JavaWeb應(yīng)用時(shí)會(huì)讀取應(yīng)用的web.xml文件,從中獲得關(guān)于當(dāng)前Web應(yīng)用的發(fā)布信息。web.xml中包含有<servlet>和<servlet-mapping>標(biāo)簽,后者配置了URL所映射的servlet,前者配置了servlet對(duì)應(yīng)的class文件。因此,在上述配置完備的情況下,只需給定一個(gè)合法的URL,web容器就能訪問(wèn)到相應(yīng)的Servlet程序。==
配置Servlet映射有兩個(gè)好處:簡(jiǎn)化Servlet的URL,并且可以向客戶端隱藏Web應(yīng)用的實(shí)現(xiàn)細(xì)節(jié);為一個(gè)Servlet對(duì)應(yīng)多個(gè)URL提供方便的設(shè)置途徑
==上述所有組件需按照上一節(jié)給出的目錄結(jié)構(gòu)部署到應(yīng)用中!==
3.4、發(fā)布JavaWeb應(yīng)用
按照你所了解的方式發(fā)布應(yīng)用即可。
四、Servlet的生命周期
Servlet是JavaWeb應(yīng)用的核心組件,熟知其生命周期有助于理解JavaWeb應(yīng)用的運(yùn)行機(jī)制。Servlet生命周期分為3個(gè)階段:
- 初始化階段:容器首先加載Servlet類,把.class文件的數(shù)據(jù)讀入內(nèi)存。接下來(lái)容器創(chuàng)建包含初始化參數(shù)的ServletConfig對(duì)象和Servlet對(duì)象,并將ServletConfig對(duì)象作為參數(shù)傳遞給Servlet對(duì)象的init(ServletConfig config)方法
- 運(yùn)行時(shí)階段:本階段中容器接收到客戶端請(qǐng)求時(shí),會(huì)代勞解析HTTP請(qǐng)求參數(shù)并創(chuàng)建針對(duì)這個(gè)請(qǐng)求的HttpServletRequest對(duì)象和HttpServletResponse對(duì)象,然后調(diào)用相應(yīng)Servlet對(duì)象的service()方法處理請(qǐng)求及生成響應(yīng)結(jié)果。容器返回結(jié)果給客戶端時(shí),會(huì)銷毀ServletRequest和ServletResponse對(duì)象
- 銷毀階段:web應(yīng)用被終止時(shí),容器首先調(diào)用所有Servlet對(duì)象的destroy()方法,然后銷毀Servlet對(duì)象和關(guān)聯(lián)的ServletConfig對(duì)象。
Servlet與JavaWeb應(yīng)用的生命周期相生相伴:
- 啟動(dòng)階段:容器在JavaWeb啟動(dòng)時(shí)將web.xml的數(shù)據(jù)加載到內(nèi)存,為JavaWeb應(yīng)用創(chuàng)建ServletContext對(duì)象,并初始化所有的過(guò)濾器和需要在應(yīng)用啟動(dòng)階段初始化的Servlet
- 運(yùn)行時(shí)階段:此階段所有Servlet處于待命狀態(tài)隨時(shí)可以響應(yīng)客戶端請(qǐng)求
- 終止階段:銷毀所有處于運(yùn)行時(shí)的Servlet對(duì)象、Filter對(duì)象及相關(guān)的對(duì)象和資源
ServletContext對(duì)象與web應(yīng)用具有同樣長(zhǎng)的生命周期,且可被應(yīng)用中的所有Web組件共享,適合存取Web應(yīng)用范圍內(nèi)的共享數(shù)據(jù)。
五、JSP技術(shù)
現(xiàn)在都流行前后端分離開(kāi)發(fā)部署了,這一章可以先放一放。
六、數(shù)據(jù)庫(kù)
6.1、JDBC存在的意義
幾乎所有的應(yīng)用軟件都離不開(kāi)數(shù)據(jù)的存儲(chǔ)和訪問(wèn),JDBC(Java DataBase Connectivity)作為Java程序和數(shù)據(jù)庫(kù)服務(wù)器通信的紐帶,其實(shí)現(xiàn)封裝了與各種數(shù)據(jù)庫(kù)服務(wù)器通信的細(xì)節(jié),為我們?cè)L問(wèn)數(shù)據(jù)庫(kù)提供了極大的便利。優(yōu)點(diǎn)列舉:
- 為開(kāi)發(fā)人員封裝好模板程序,如建立數(shù)據(jù)庫(kù)連接,釋放資源等操作,簡(jiǎn)化了訪問(wèn)數(shù)據(jù)庫(kù)的程序代碼,Java程序直接調(diào)用JDBC API即可訪問(wèn)數(shù)據(jù)庫(kù),無(wú)須涉及與數(shù)據(jù)庫(kù)服務(wù)器通信的細(xì)節(jié)
- 不依賴特定數(shù)據(jù)庫(kù)平臺(tái),各家數(shù)據(jù)庫(kù)廠商均已基于自身產(chǎn)品特點(diǎn)實(shí)現(xiàn)了JDBC,應(yīng)用程序只需引入對(duì)應(yīng)廠商實(shí)現(xiàn)的JDBC jar包,即可在多種數(shù)據(jù)庫(kù)平臺(tái)間無(wú)縫遷移
6.2、如何進(jìn)行數(shù)據(jù)庫(kù)驅(qū)動(dòng)
JDBC的實(shí)現(xiàn)包含3個(gè)部分:
- JDBC驅(qū)動(dòng)管理器:主要是java.sql.DriverManager類。負(fù)責(zé)注冊(cè)特定JDBC驅(qū)動(dòng)程序
- JDBC驅(qū)動(dòng)程序API:主要接口是java.sql.Driver,各數(shù)據(jù)庫(kù)廠商或第三方需實(shí)現(xiàn)此接口完成JDBC驅(qū)動(dòng)程序的功能實(shí)現(xiàn)
- JDBC驅(qū)動(dòng)程序:JDBC驅(qū)動(dòng)程序API的實(shí)現(xiàn),負(fù)責(zé)特定數(shù)據(jù)庫(kù)的連接、處理通信細(xì)節(jié)等。
綜上,JDBC驅(qū)動(dòng)程序是真正的連接Java應(yīng)用程序與數(shù)據(jù)庫(kù)的紐帶。Java應(yīng)用程序如果希望訪問(wèn)某種數(shù)據(jù)庫(kù),必須先獲得相應(yīng)的JDBC驅(qū)動(dòng)程序類庫(kù),然后將其注冊(cè)到JDBC驅(qū)動(dòng)程序管理器。通過(guò)DriverManager提供的getConnection方法建立數(shù)據(jù)庫(kù)Connection,通過(guò)在數(shù)據(jù)庫(kù)連接url中添加前綴來(lái)指定要驅(qū)動(dòng)的數(shù)據(jù)庫(kù)程序:
String url= "jdbc:mysql://127.0.0.1:3306/mi_user";
Connection con=DriverManager.getConnection(url,userName,pwd);
JDBC驅(qū)動(dòng)程序管理器運(yùn)用了橋梁設(shè)計(jì)模式,橋接模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,它的主要特點(diǎn)是把抽象與行為實(shí)現(xiàn)分離開(kāi)來(lái),分別定義接口,可以保持各部分的獨(dú)立性以及應(yīng)對(duì)他們的功能擴(kuò)展。橋梁模式使得應(yīng)用程序只需和JDBC API打交道,JBC API依賴DriverManager類管理JDBC驅(qū)動(dòng)程序。當(dāng)應(yīng)用程序需要向數(shù)據(jù)庫(kù)提交任務(wù)時(shí),DriverManager類會(huì)委派特定的驅(qū)動(dòng)程序來(lái)執(zhí)行任務(wù)。
JDBC驅(qū)動(dòng)程序加載過(guò)程
6.3、數(shù)據(jù)源(DataSource)簡(jiǎn)介
建立數(shù)據(jù)庫(kù)連接消耗:
- 為連接分配系統(tǒng)資源
- 數(shù)據(jù)庫(kù)服務(wù)端校驗(yàn)用戶名和密碼
- Java程序?qū)⒋磉B接的java.sql.connection對(duì)象加載到內(nèi)存中
可見(jiàn)每次與數(shù)據(jù)庫(kù)建立連接的開(kāi)銷很大。而數(shù)據(jù)源會(huì)事先建立多個(gè)數(shù)據(jù)庫(kù)連接,并保存在連接池中,當(dāng)應(yīng)用程序需要訪問(wèn)數(shù)據(jù)庫(kù)時(shí),直接從池中取出空閑狀態(tài)的數(shù)據(jù)庫(kù)連接,使用完成后再放回連接池以此提高訪問(wèn)數(shù)據(jù)庫(kù)的效率,降低資源開(kāi)銷。
6.4、小結(jié)
數(shù)據(jù)庫(kù)相關(guān)技術(shù)使得我們的應(yīng)用程序與數(shù)據(jù)庫(kù)連接是松耦合的,它通過(guò)封裝了目標(biāo)源的位置信息,驗(yàn)證信息、建立與關(guān)閉連接的操作,為我們屏蔽了底層數(shù)據(jù)庫(kù)的差異和繁瑣操縱過(guò)程。
開(kāi)發(fā)人員只需在配置文件中指定數(shù)據(jù)源類型,數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序和目標(biāo)源的URL,框架或容器就會(huì)幫助我們完成Driver的注冊(cè),然后利用數(shù)據(jù)源實(shí)現(xiàn)特定數(shù)據(jù)庫(kù)的連接并根據(jù)配置信息對(duì)連接進(jìn)行池話。當(dāng)應(yīng)用程序想要訪問(wèn)數(shù)據(jù)庫(kù)時(shí),只需從數(shù)據(jù)源中取出連接使用即可,其他的一切過(guò)程對(duì)開(kāi)發(fā)人員來(lái)說(shuō)都是透明的。當(dāng)某一天想要使用新的數(shù)據(jù)庫(kù)技術(shù)來(lái)替代時(shí),無(wú)需修改代碼,替換配置即可。
7、HTTP會(huì)話與管理
8、開(kāi)發(fā)Javamail Web應(yīng)用
9、Web應(yīng)用的MVC設(shè)計(jì)模式
MVC和核心設(shè)計(jì)理念是組件化,解耦合。