- 微服務從小白到專家:Spring Cloud和Kubernetes實戰
- 姚秋辰 張昕 卿睿
- 5293字
- 2021-10-29 12:24:22
1.2 Java Web開發的進化史
Web應用最初是指通過Web瀏覽器提供用戶界面的軟件系統,例如博客、網上購物、搜索引擎等。后來隨著RESTful Services、微服務等概念的興起,各種API也被包含在Web應用的范疇。
Web應用程序很簡單,僅由靜態或動態交互式的頁面組成。靜態頁面存儲在Web服務器的文件系統中,向所有訪問者顯示固定的內容。而動態頁面是由動態生成HTML的程序構建的。這種類型的Web應用程序可以根據不同用戶的請求提供各種不同的信息,目前主流的Web應用都是動態應用。
那么Web應用是如何工作的呢?通常,訪問一個靜態Web應用的步驟如下:
(1)用戶在瀏覽器中輸入URL。
(2)瀏覽器通過互聯網向Web服務器發送請求。
(3)Web服務器檢查請求,并基于請求服務器查找其本地存在的靜態頁面。
(4)Web服務器將響應發送到瀏覽器。
(5)瀏覽器獲取HTML及相關資源,最終渲染為完整的用戶可視化界面。
靜態Web應用的訪問過程如圖1-9所示。

圖1-9 靜態Web應用訪問過程示例
動態Web應用的內容根據用戶請求的差異而有所不同。在Java生態中,最初是以Servlet規范和JSP規范來支持動態Web開發的。對于這種類型的應用程序,Web服務器通過Servlet插件構建動態頁面,Servlet插件也稱為Servlet容器。動態Web應用的訪問過程如圖1-10所示。

圖1-10 動態Web應用的訪問過程
1.2.1 應用服務器
1.2.1.1 什么是應用服務器
在Java生態中,構建動態Web應用需要借助Servlet容器。提供Servlet容器功能的軟件就是應用服務器,而只能提供靜態資源訪問能力的軟件則被稱為Web服務器。Servlet容器也被稱為Servlet引擎,它為Java Servlet組件提供了非常高效的運行環境。
主流的應用服務器既可以作為Servlet容器,也可以充當Web服務器,這種將Servlet容器和Web服務器合二為一的方式在開發階段比較常見,便于開發團隊調試應用程序。但我們不建議在正式的生產環境中使用,因為兩種服務器的核心功能是完全不同的,應當各司其職。
目前,主流的部署方式是使用Web服務器處理所有的靜態請求,并通過特定的連接方式與應用服務器相連,將動態請求交由應用服務器處理,然后由Web服務器一并返回客戶端。
在當前的Java生態中,主流的Java應用服務器有Apache Tomcat、GlassFish、Jetty、JBoss等,下面將以Apache Tomcat為例,演示如何將Java Web應用部署到應用服務器,以供客戶端訪問。
1.2.1.2 Apache Tomcat下載和安裝
我們可以直接從官網下載Apache Tomcat,根據應用程序所使用的各種規范版本(比如JDK版本)的不同,其所需的Apache Tomcat版本也不一樣,請讀者參考Apache Tomcat的官方規范兼容文檔選擇正確的Apache Tomcat版本。在本書中筆者使用JDK 8進行開發,因此選擇了能支持JDK 8的最低兼容版本Apache Tomcat 9。
從官網下載壓縮包apache-tomcat-9.0.41.zip,并解壓縮,其目錄結構如圖1-11所示。

圖1-11 Apache Tomcat目錄結構
圖1-11中目錄的具體功能如下:
? bin:它用于存放批處理和shell腳本,例如Apache Tomcat的開始和停止的相關腳本,其內容如圖1-12所示。

圖1-12 Apache Tomcat bin目錄
? conf:它用于存放Apache Tomcat相關配置文件,其內容如圖1-13所示。

圖1-13 Apache Tomcat conf目錄
? lib:Apache Tomcat服務器依賴項目庫目錄,其中包含Apache Tomcat服務器運行環境所需的jar包,其內容如圖1-14所示。

圖1-14 Apache Tomcat lib目錄
? webapps:Apache Tomcat的默認Web應用程序部署目錄,即打包出的Java Web應用將會被放在該目錄,如圖1-15所示。

圖1-15 Apache Tomcat webapps目錄
在了解了各個目錄的基本功能以后,接下來我們驗證解壓后的Apache Tomcat是否可以正常工作。在命令行界面進入bin目錄運行startup.sh文件,對使用macOS的用戶來說,如果命令行界面出現類似“Cannot find ./catalina.sh”的錯誤,說明當前系統用戶對該目錄下的腳本沒有執行權限,需要運行以下命令對操作用戶賦權:

成功啟動Apache Tomcat的日志如圖1-16所示。

圖1-16 Tomcat啟動成功日志
如果Apache Tomcat以默認配置啟動,打開任意瀏覽器并輸入http://localhost:8080,就可以訪問Apache Tomcat的管理界面,如圖1-17所示。

圖1-17 Apache Tomcat的管理界面
1.2.2 青銅Servlet
從Java Web應用的發展歷程來看,Servlet技術是Java對Web應用的早期支持方式,當我們回過頭來看當年的Servlet和Java Web技術,就如同回顧人類歷史上的青銅時代。
1.2.2.1 什么是Servlet
Servlet是一個新造詞,是由server(服務器)和let(表示很小的東西的詞根)而來,因此,Servlet顧名思義表示一種小型的服務。
一個Servlet就是一個Java類,它主要用于擴展處理請求——響應應用服務器處理請求的能力。對于此類應用程序,Java Servlet技術定義了特定于HTTP的Servlet類。
我們可以將Servlet看成是在服務器上運行的Java應用程序編程接口(API),它攔截客戶端發出的請求并生成與之對應的響應。在Servlet規范中,javax.servlet包和javax.servlet.http包提供用于編寫Servlet的接口和類。
在Servlet容器中,一個Servlet是何時被創建又在何時被銷毀的呢?在Servlet規范中,諸如Servlet創建和Servlet銷毀之類的行為被稱為Servlet的生命周期。在了解Servlet生命周期之前,需要先簡單了解Servlet接口。
javax.servlet.servlet接口的定義如表1-1所示(未全部列出)。
表1-1 Servlet接口定義

Servlet的生命周期如圖1-18所示。

圖1-18 Servlet生命周期
下面介紹生命周期的5個步驟。
(1)加載Servlet類
當容器收到對Servlet的第一個請求時,類加載器會加載Servlet類。
(2)創建Servlet實例
容器在加載Servlet類后創建Servlet實例,Servlet實例在Servlet生命周期中只創建一次。
(3)調用init()方法
init()方法用于初始化Servlet。它是javax.servlet.Servlet接口的生命周期方法。容器在創建Servlet實例后只調用init()方法一次。
(4)調用Service()方法
Servlet容器在收到用戶請求時,會嘗試調用Servlet實例的service()方法。如果Servlet尚未被實例化,則執行步驟(1)~(3),再調用service()方法。
(5)調用destroy()方法
Servlet容器在刪除Servlet實例之前將調用該實例的destroy()方法。destroy()方法為服務器提供了清理資源(例如內存、線程等)的機會。
1.2.2.2 使用Servlet實現HelloWorld
首先,創建一個Servlet的項目,目前Maven的archetype已經不再支持最新版的Servlet規范,所以需要有一些前提準備。
創建新的項目可以通過Maven或IDE來直接創建,本節將演示如何使用IntelliJ IDEA來創建一個Servlet項目。
(1)在IntelliJ IDEA中選擇新建項目,其界面如圖1-19所示。

圖1-19 IntelliJ IDEA創建項目
(2)選擇從archetype創建項目,所選archetype類型為maven-archetype-webapp,然后單擊Next按鈕,其界面如圖1-20所示。

圖1-20 IntelliJ利用archetype創建項目
(3)輸入項目名servlet-demo,填寫項目路徑、GroupId、ArtifactId,再單擊Next按鈕即可,指定項目信息如圖1-21所示。

圖1-21 指定項目信息
項目創建成功,其結構如圖1-22所示。

圖1-22 Servlet項目結構
目前,Maven和Servlet的最新版存在兼容性問題,需要webapp/WEB-INF/web.xml文件做一些修改,由于其默認支持Servlet 2.3,所以讀者需要手動添加依賴,具體代碼如下:

基于Servlet 4規范創建Servlet程序有兩種方式,第一種是傳統的使用web.xml注冊的方式,第二種是新型的使用WebServlet注釋的方式,第一種方式的執行步驟如下。
第一步:實現Servlet類。實現Servlet有三種方式:實現Servlet接口、繼承GenericServlet類、繼承HttpServlet類。
本示例程序以繼承HttpServlet類的方式實現,示例代碼如下:

第二步:注冊Servlet。
編輯src/main/webapp/WEB-INF/web.xml文件即可注冊Servlet,代碼如下:

如上代碼所示,Servlet注冊信息主要有兩項內容:
? 通過<Servlet-name>標簽注冊com.broadview.servlet.OldServlet,并將其命名為oldDemo。
? 通過<url-pattern>標簽注冊訪問oldDemo Servlet的URL,即/old。
由上可知,注冊信息的主要目的是定義訪問URL與Servlet之間的映射關系。
第三步:編譯打包。
進入項目的根目錄,并運行打包命令:

命令運行完畢,項目的target目錄會產生一個名為servlet-demo.war的文件,將此文件復制到1.2.1.2節所安裝的Tomcat的webapps目錄下。
第四步:添加Tomcat的管理權限。
在啟動Tomcat之前還需要為Tomcat設置管理員權限,進入Tomcat的config目錄,打開tomcat-users.xml文件,在該文件中添加以下代碼:

第五步:啟動Tomcat。
進入Tomcat的bin目錄運行以下命令:

如果Tomcat安裝正常,Servlet項目編寫、編譯和打包無誤,則會出現Tomcat started的啟動日志。
下面驗證Servlet應用是否能夠正常啟動,打開瀏覽器輸入http://localhost:8080/,進入Tomcat的管理界面,如圖1-23所示,此界面有管理Web應用的功能,單擊Manager App按鈕,輸入在tomcat-users.xml中配置的用戶名和密碼,進入Tomcat Web應用的管理界面,如圖1-24所示。

圖1-23 Tomcat管理界面

圖1-24 Tomcat Web應用管理界面
從圖1-24可見servlet-demo項目顯示在應用程序列表中,單擊該項目鏈接,會跳轉到該項目的主頁界面,如圖1-25所示。

圖1-25 項目主頁界面
由于Servlet實現了doGet()方法,所以用戶可以通過http://localhost:8080/servlet-demo/old來訪問此Servlet,URL中的servlet-demo部分為context path,訪問servlet-demo項目下的所有API都需要包含此路徑。URL中結尾處的“old”的作用是,將當前請求轉發到指定的Servlet實例。
在瀏覽器中輸入http://localhost:8080/servlet-demo/old,就可以查看對應Servlet的輸出,如圖1-26所示。

圖1-26 Servlet的輸出
上面這種需要在web.xml中注冊Servlet的方式是早期的Servlet開發方式,下面是使用WebServlet注釋的方式創建Servlet的示例代碼。

再重新打包編譯并復制war文件到Tomcat的webapps目錄。通過http://localhost:8080/servlet-demo/new訪問新的Servlet,其效果如圖1-27所示。

圖1-27 新式Servlet輸出
這種新方式無需在web.xml中注冊Servlet,編程體驗更加簡潔優雅。但是無論如何Servlet的開發方式都是相對原始的,其開發效率很難滿足當前多變的復雜的業務需求。因此,業界發明了更多的新技術以滿足日益增長的用戶需求。
1.2.3 鉑金Spring MVC
正如1.2.2節中所述,Servlet技術無法滿足日益復雜的業務需求,市場自然就會出現可以填補這種需求空白的技術,因此Spring MVC應運而生。
1.2.3.1 什么是Spring MVC
在了解Spring MVC之前,先簡單介紹一下MVC。MVC是一種實現應用程序表現層的常用模式,此模式定義了不同的組件、組件的職責及不同組件之間的關系。MVC模式有三個概念:
? 模型(Model):模型表示業務數據及用戶上下文中應用程序的“狀態”,例如電商網站中的訂單、用戶、物流信息等都屬于模型的范疇。
? 視圖(View):以某種特定的方式向用戶展示數據,可以簡單地理解為用戶界面,也支持與用戶的交互。
? 控制器(Controller):控制器處理前端用戶發送的操作請求、與服務層交互、更新模型,并根據執行結果將用戶定向到相應的視圖。
Spring MVC模塊為MVC模式提供了全面支持,它結合MVC模式的所有優點和Spring的便利性,使用DispatcherServlet實現了前端控制器模式(Front Controller Pattern)。
圖1-28描述了Spring MVC的主要組件和請求處理的流程。其中,通用服務為各類組件提供各種工具,包括i18n、主題和文件上傳。它們的配置定義在DispatcherServlet的WebApplicationContext中。

圖1-28 Spring MVC處理流程
圖1-28中的關鍵組件介紹如下:
? Filter:過濾器適用于每個請求,下一節將介紹幾種常用的過濾器及其用途。
? DispatcherServlet:DispatcherServlet分析請求并調度到相應的控制器進行處理。
? Handler Mapping:將傳入的請求映射到相應的處理程序(Spring MVC控制器類中的方法)。自Spring 2.5以來,在大多數情況下不需要配置,因為Spring MVC將自動注冊一個處理程序映射的實現,該實現是基于class或方法級別的@RequestMapping注解。
? Handler Interceptor:在Spring MVC中,可以注冊處理程序的攔截器,以實現常見的檢查邏輯。
? Handler Exception Resolver:在Spring MVC中,程序異常解析器接口(在org.springframe.Web.servlet中定義)旨在處理程序在處理請求期間拋出的異常。解析程序通過設置特定的響應狀態代碼處理某些標準的Spring MVC異常。此外也可通過@ExceptionHandler注解來處理異常程序。
? View解析器:Spring MVC控制器方法通常會返回邏輯視圖,想要定位到真正的頁面,可以通過View解析器來實現。
? View:View可以是物理視圖也可以是模板,Spring MVC會解析邏輯視圖配置,返回一種Freemarker模板或thymelea模板,該模板用于將數據模型中的數據合并到模板中,從而生成標準的輸出文本,包括HTML、XML、Java源碼等。
1.2.3.2 使用Spring MVC實現HelloWorld
使用Spring MVC實現HelloWorld,與直接使用Servlet構建HelloWorld類似,需要先創建一個Web應用項目,具體步驟請參照1.2.2.2節。
然后,在pom.xml文件中添加相關依賴項,具體代碼如下:


與定義傳統Servlet一樣,Spring MVC需要在web.xml中定義Servlet映射,具體代碼如下:

根據上面代碼中定義的servlet-name,按照Spring MVC的規范創建相應的Spring Bean的定義文件springmvcDemo-servlet.xml,具體代碼如下:

下面,我們來創建一個DemoController類,并定義一個方法來處理用戶請求,具體代碼如下:

在上述代碼中,@RestController注解表明DemoController類是被Spring MVC托管的controller類,@RequestMapping注解定義了訪問Service的方式。參照1.2.2節中的步驟使用mvn命令將項目打包,再將編譯后的springmvc-demo.war文件復制到Tomcat的webapps目錄下,重新啟動Tomcat(如果Tomcat是一直運行的,且本身是可以熱加載的,則無需重啟),再從瀏覽器中輸入http://localhost:8080/springmvc-demo/mvcdemo訪問Spring MVC應用,運行效果如圖1-29所示。

圖1-29 Spring MVC的運行效果
相較于傳統的Servlet,Spring MVC代碼簡潔了許多,只是額外多了DispatchServlet的Spring Bean配置文件。Spring MVC的功能十分豐富,本章只是做了基本演示,其他細節知識,請讀者通過Spring官網探索。
1.2.4 王者Spring Boot
1.2.4.1 什么是Spring Boot
雖然Spring MVC相較于傳統Servlet已經相對簡化,但仍需要web.xml和相應的Spring Bean的配置,這些文件煩瑣而又不可缺,從廣大開發者的角度出發,如果可以進一步省略這些文件,不但可以減少代碼量,而且可以使代碼更加優雅整潔。所以Spring Boot正是秉承約定大于配置(Convention Over Configuration)的精神出現了。
Spring Boot的主要目標是簡化傳統Spring應用的開發過程。使用Spring Boot可以減少大量的配置文件,其內置的Servlet容器可以簡化應用的部署過程,簡潔易用的工具可以使開發者從重復性工作中得到解放。簡而言之,Spring Boot并非要替代Spring框架,而是要簡化基于Spring框架的開發工作。
本章只是簡要地介紹Spring Boot應用開發的便利性,第2章我們將借助實戰項目深入了解Spring Boot。
1.2.4.2 使用Spring Boot實現HelloWorld
首先,我們通過Spring Boot Initializr官網來創建一個簡單的Spring Boot項目。打開Spring Boot Initializr官網選擇合適的Spring Boot版本及所需要的依賴,就可以創建一個Spring Boot項目,Spring Boot項目創建界面如圖1-30所示。

圖1-30 Spring Boot項目創建界面
然后,將產生的項目文件導入IDE中,Spring Boot項目默認有一個Spring Boot啟動類,在本例中啟動類是SpringbootdemoApplication,該類的定義代碼如下:

再創建一個DemoController類,實現一個HelloWorld,具體代碼如下:

只需以上兩個簡單的類,一個基于Spring Boot的簡版Web Service就創建成功了,此外,該項目在開發階段可以直接從IDE運行,無需額外的打包和部署操作。因為Spring Boot內置了Servlet容器(默認為Tomcat),所以Spring Boot項目可以直接運行。在本例中直接運行SpringbootdemoApplication類的main()方法即可(此類為應用啟動類),在IDE中運行方式如圖1-31所示。

圖1-31 在IDE中運行Spring Boot項目
如果一切運行正常,那么該應用會默認監聽8080端口。在瀏覽器中輸入http://localhost:8080/bootdemo,驗證應用是否正常啟動,Spring Boot運行效果如圖1-32所示。

圖1-32 Spring Boot運行效果
相對于Servlet和Spring MVC,基于Spring Boot構建的應用從代碼到配置都做了極大的簡化。
本章逐一使用不同時期的主流技術進行開發,理解這些技術之間的差異性是成為一名合格程序員的基本功,深入研究技術背后的工作原理是程序員進階的必備手段。在本書的后續章節,我們將深入了解各個技術的實現細節,來理解其背后的工作原理。就全書而言,本章只是一場簡單的熱身運動,后續的精彩內容將為各位讀者一一呈現。
- Learning Python Web Penetration Testing
- Python自然語言處理實戰:核心技術與算法
- Leap Motion Development Essentials
- Visual Basic程序設計教程
- C#程序設計(慕課版)
- 機器人Python青少年編程開發實例
- 精通Linux(第2版)
- Yii Project Blueprints
- HTML5與CSS3權威指南
- Monitoring Docker
- 金融商業數據分析:基于Python和SAS
- Learning Shiny
- Distributed Computing with Python
- 前端程序員面試算法寶典
- PyTorch生成對抗網絡編程