感興趣的朋友,可以關(guān)注微信服務(wù)號(hào)“猿學(xué)堂社區(qū)”采桃,或加入“猿學(xué)堂社區(qū)”微信交流群
版權(quán)聲明:本文由作者自行翻譯橙凳,未經(jīng)作者授權(quán),不得隨意轉(zhuǎn)發(fā)彭羹。
該指南是Vert.x異步編程的一個(gè)入門(mén)介紹黄伊,主要針對(duì)那些熟悉主流、非異步Web開(kāi)發(fā)框架和庫(kù)(如Java EE派殷、Spring)的開(kāi)發(fā)者还最。
1.1 關(guān)于該手冊(cè)
我們假定讀者已經(jīng)熟悉Java編程語(yǔ)言及其生態(tài)系統(tǒng)墓阀。
我們將以一個(gè)Wiki Web應(yīng)用作為開(kāi)始,它開(kāi)始采用關(guān)系數(shù)據(jù)庫(kù)和服務(wù)端頁(yè)面渲染拓轻;然后我們通過(guò)幾個(gè)步驟逐步演進(jìn)該應(yīng)用岂津,直到它成為一個(gè)現(xiàn)代的單頁(yè)應(yīng)用,并且擁有實(shí)時(shí)Web的特征【注意悦即,術(shù)語(yǔ)“實(shí)時(shí)”在Web技術(shù)環(huán)境中的廣泛使用不應(yīng)與專(zhuān)業(yè)操作系統(tǒng)中的硬或軟實(shí)時(shí)混淆】。在這個(gè)過(guò)程中橱乱,你將學(xué)會(huì):
- 設(shè)計(jì)一個(gè)Web應(yīng)用辜梳,它通過(guò)模板進(jìn)行服務(wù)端頁(yè)面渲染,并且使用關(guān)系型數(shù)據(jù)庫(kù)持久化數(shù)據(jù)泳叠。
- 清晰的隔離每個(gè)技術(shù)組件作瞄,使之成為一個(gè)可復(fù)用的事件處理單元,稱(chēng)為verticle危纫。
- 為了方便Verticle設(shè)計(jì)宗挥,而抽取Vert.x服務(wù)。Verticle可以在同一個(gè)JVM進(jìn)程中或集群中的分布式節(jié)點(diǎn)之間無(wú)縫通訊种蝶。
- 測(cè)試異步操作代碼契耿。
- 與公開(kāi)HTTP/JSON Web API的第三方服務(wù)集成。
- 公開(kāi)HTTP/JSON Web API螃征。
- 采用HTTPS的安全和訪問(wèn)控制搪桂,針對(duì)Web瀏覽器會(huì)話的用戶(hù)認(rèn)證以及針對(duì)第三方客戶(hù)端應(yīng)用的JWT Token。
- 通過(guò)流行的RxJava庫(kù)及其相關(guān)的Vert.x集成盯滚,采用響應(yīng)式編程重構(gòu)部分代碼踢械。
- 采用AngularJS的單頁(yè)應(yīng)用的客戶(hù)端編程。
- 基于SockJS魄藕,使用統(tǒng)一Vert.x事件總線集成的實(shí)時(shí)Web編程内列。
該文檔和示例代碼的源文件位于https://github.com/vert-x3/vertx-guide-for-java-devs。我們歡迎問(wèn)題報(bào)告背率、反饋和Pull Request话瞧。
1.2 什么是Vert.x
Eclipse Vert.x是一個(gè)基于JVM構(gòu)建響應(yīng)式應(yīng)用的工具包。
——Vert.x網(wǎng)站
Eclipse Vert.x(接下來(lái)的文檔中我們僅稱(chēng)為Vert.x)是Eclipse基金會(huì)下的一個(gè)開(kāi)源項(xiàng)目寝姿。Vert.x于2012年由Tim Fox發(fā)起移稳。
Vert.x不是一個(gè)框架,而是一個(gè)工具包:它的核心庫(kù)定義了編寫(xiě)異步網(wǎng)絡(luò)應(yīng)用的基本API会油,你可以為應(yīng)用程序選擇有用的模塊(如數(shù)據(jù)庫(kù)鏈接个粱、監(jiān)控、認(rèn)證翻翩、日志都许、服務(wù)發(fā)現(xiàn)稻薇、集群支持等)。Vert.x基于Netty項(xiàng)目——一個(gè)基于JVM的高性能異步網(wǎng)絡(luò)庫(kù)胶征。如果需要塞椎,Vert.x允許你訪問(wèn)Netty內(nèi)部,但是通常情況下你會(huì)受益于Vert.x提供的高級(jí)API睛低,而且與原始Netty相比并不犧牲性能案狠。
Vert.x不強(qiáng)制要求打包方式或者構(gòu)建環(huán)境。由于Vert.x Core本身只是一個(gè)普通的JAR庫(kù)钱雷,所以它可以嵌入到應(yīng)用程序內(nèi)部骂铁,無(wú)論這些應(yīng)用是打包為一組JAR、一個(gè)包含所有依賴(lài)的單獨(dú)的JAR罩抗、或者即使被部署到流行的組件和應(yīng)用容器拉庵。
由于Vert.x設(shè)計(jì)用于異步通信,因此它可以處理更多的并發(fā)網(wǎng)絡(luò)連接套蒂,且比諸如Java Servlet或者java.net.socket類(lèi)等同步API使用更少的線程钞支。Vert.x可以用于廣泛的應(yīng)用程序:大容量消息/事件處理、微服務(wù)操刀、API網(wǎng)關(guān)烁挟、移動(dòng)應(yīng)用HTTP API,等骨坑。Vert.x及其生態(tài)提供了構(gòu)建端到端響應(yīng)式應(yīng)用的各種技術(shù)工具信夫。
盡管可能聽(tīng)起來(lái)Vert.x只適用于要求苛刻的應(yīng)用,本指南同樣說(shuō)明Vert.x對(duì)于更多傳統(tǒng)的Web應(yīng)用也工作良好卡啰。正如我們將看到的静稻,代碼將保持相對(duì)容易理解,但是匈辱,如果應(yīng)用程序需要面對(duì)流量的突然峰值振湾,那么代碼已經(jīng)使用可擴(kuò)展的基本組件編寫(xiě):事件的異步處理。
最后亡脸,值得一提的是押搪,Vert.x是多語(yǔ)言的,它支持廣泛的流行的JVM語(yǔ)言:Java浅碾、Groovy大州、Scala、Kotlin垂谢、JavaScript厦画、Ruby及Ceylon。當(dāng)Vert.x支持一種語(yǔ)言時(shí),它的目標(biāo)并不只是提供訪問(wèn)API根暑,還要確保在每種目標(biāo)語(yǔ)言中力试,特定語(yǔ)言的API是符合語(yǔ)言習(xí)慣的(如,使用Scala future替換Vert.x future)排嫌。使用不同的JVM語(yǔ)言開(kāi)發(fā)Vert.x應(yīng)用程序的不同技術(shù)部分是非常有可能的畸裳。
1.3 Vert.x核心概念
在Vert.x中有兩個(gè)關(guān)鍵的概念需要學(xué)習(xí):
- 什么是Verticle
- 事件總線如何讓Verticle之間通訊
1.3.1 線程和編程模型
許多網(wǎng)絡(luò)庫(kù)和框架依靠一個(gè)簡(jiǎn)單的線程策略:每個(gè)網(wǎng)絡(luò)客戶(hù)端在鏈接時(shí)被分配一個(gè)線程,這個(gè)線程處理這個(gè)客戶(hù)端的請(qǐng)求淳地,直到鏈接斷開(kāi)怖糊。這是Servlet以及使用java.io和java.net包編寫(xiě)網(wǎng)絡(luò)代碼的情況。雖然這種“同步I/O”線程模型具有簡(jiǎn)單易懂的優(yōu)點(diǎn)颇象,但是當(dāng)存在太多并發(fā)鏈接時(shí)伍伤,它會(huì)損害可伸縮性,因?yàn)橄到y(tǒng)線程并非廉價(jià)夯到,并且在高負(fù)載的情況下,操作系統(tǒng)內(nèi)核在線程調(diào)度管理上花費(fèi)顯著的時(shí)間饮亏。在這種情況下耍贾,我們需要轉(zhuǎn)移到“異步I/O”,Vert.x則為“異步I/O”提供了堅(jiān)實(shí)的基礎(chǔ)路幸。
Vert.x中的部署單元稱(chēng)為Verticle荐开。一個(gè)Verticle通過(guò)一個(gè)事件循環(huán)(EventLoop)處理接收到的事件,這些事件可以是任何事情简肴,如接收網(wǎng)絡(luò)緩沖晃听、調(diào)度事件或由其它Verticle發(fā)送的消息。事件循環(huán)(EventLoop)是異步編程模型中是特有的:
每個(gè)事件應(yīng)在合理的時(shí)間內(nèi)進(jìn)行處理砰识,以免阻塞事件循環(huán)(EventLoop)能扒。這意味著當(dāng)在事件循環(huán)(EventLoop)中執(zhí)行時(shí),不能進(jìn)行線程阻塞操作辫狼,類(lèi)似在一個(gè)GUI中處理事件(如通過(guò)執(zhí)行一個(gè)緩慢的網(wǎng)絡(luò)請(qǐng)求可以?xún)鼋Y(jié)Java/Swing界面)初斑。如我們?cè)诒局改辖酉聛?lái)看到的,Vert.x在事件循環(huán)(EventLoop)的外部提供了處理阻塞操作的機(jī)制膨处。在任何情況下见秤,事件循環(huán)(EventLoop)執(zhí)行事件的時(shí)間過(guò)長(zhǎng)時(shí),Vert.x會(huì)在日志中輸出警告真椿,這是可配置的鹃答,以滿(mǎn)足特定應(yīng)用需求(如當(dāng)工作于較慢的IoT ARM板時(shí))。
每個(gè)事件循環(huán)(EventLoop)連接到一個(gè)線程突硝。默認(rèn)情況下测摔,Vert.x為每個(gè)CPU內(nèi)核線程賦予2個(gè)事件循環(huán)(EventLoop)。這直接導(dǎo)致了常規(guī)的Verticle總是在同一個(gè)線程中處理事件解恰,因此不需要使用線程協(xié)調(diào)機(jī)制來(lái)操作Verticle狀態(tài)(如Java類(lèi)屬性)避咆。
Verticle可以被傳遞一些配置信息(如證書(shū)舟肉、網(wǎng)絡(luò)地址等),而且Verticle可以被多次部署:
到達(dá)的網(wǎng)絡(luò)數(shù)據(jù)從接收線程中接收查库,然后作為事件被傳遞給相應(yīng)的Verticle路媚。當(dāng)一個(gè)Verticle打開(kāi)了網(wǎng)絡(luò)服務(wù)器并且被部署了多次時(shí),那么事件會(huì)按照輪詢(xún)的方式分發(fā)到Verticle實(shí)例樊销,這對(duì)于在大量并發(fā)網(wǎng)絡(luò)請(qǐng)求時(shí)最大化CPU使用率是非常有用的整慎。最后,Verticle擁有一個(gè)簡(jiǎn)單的啟動(dòng)/停止生命周期围苫,Verticle可以部署其它Verticle裤园。
1.3.2 事件總線
在Vert.x中,Verticle構(gòu)成了代碼部署的技術(shù)單元剂府。Vert.x事件總線是在不同Verticle之間通過(guò)異步消息傳遞進(jìn)行通訊的主要工具拧揽。例如,假設(shè)我們有一個(gè)Verticle用于處理HTTP請(qǐng)求腺占,一個(gè)Verticle用于管理數(shù)據(jù)庫(kù)訪問(wèn)淤袜。事件總線允許HTTP Verticle發(fā)送一個(gè)請(qǐng)求到數(shù)據(jù)庫(kù)Verticle,執(zhí)行一個(gè)SQL查詢(xún)衰伯,并響應(yīng)HTTP Verticle:
事件總線允許傳遞任何類(lèi)型的數(shù)據(jù)铡羡,然而JSON是首選的交換格式,因?yàn)樗试S不同語(yǔ)言編寫(xiě)的Verticle之間進(jìn)行通訊意鲸,并且更一般地烦周,JSON是一種流行的通用半結(jié)構(gòu)化數(shù)據(jù)封送處理文本格式。
消息可以發(fā)送到任意自由字符串組成的目的地怎顾。事件總線支持以下通訊方式:
- 端到端的消息
- 請(qǐng)求——響應(yīng)消息
- 發(fā)布/訂閱用于廣播消息
事件總線允許Verticle之間透明的通訊读慎,不只是在同一個(gè)JVM進(jìn)程中:
- 當(dāng)網(wǎng)絡(luò)集群?jiǎn)?dòng)時(shí),事件總線是分布式的槐雾,因此消息可以被發(fā)送到運(yùn)行于其它應(yīng)用節(jié)點(diǎn)的Verticle贪壳。
- 事件總線可以通過(guò)一個(gè)簡(jiǎn)單的TCP協(xié)議訪問(wèn),以便第三方應(yīng)用進(jìn)行通訊蚜退。
- 事件總線還可以通過(guò)通用消息橋公開(kāi)(如AMQP闰靴、Stomp)。
- SockJS橋接允許Web應(yīng)用通過(guò)運(yùn)行在瀏覽器中的JavaScript與事件總線無(wú)縫通訊钻注,與任何Verticle一樣接收與發(fā)布消息蚂且。