1. 關(guān)于Vert.x
1.1 Vertx是什么
在學(xué)習(xí)Vert.x前一定要看看官網(wǎng)給他的定位
Eclipse Vert.x is a tool-kit for building reactive applications on the JVM.
所以,我們必須首先搞清楚,Vertx不是類似Spring的那一套大而全的框架或者管理對(duì)象的容器、工廠
盡管我們不能期待它承擔(dān)一個(gè)完整的項(xiàng)目腳手架的角色,但是麻雀雖小,五臟俱全,作為一個(gè)工具集,它包含web服務(wù)器應(yīng)用(其中又包含對(duì)http協(xié)議、http2、序列化及反序列化、驗(yàn)證、鑒權(quán)等的支持)、數(shù)據(jù)庫(kù)客戶端、服務(wù)通信組件等模塊,我們可以根據(jù)需要自行組合他們
其中的Vertx core是底層組件,它基于Netty構(gòu)建而成,其中的核心概念有:
- Vertx實(shí)例:Vertx的控制中心,承擔(dān)對(duì)Verticle、event loop等組件的配置、啟動(dòng)等任務(wù)
- Event Loop:Vertx應(yīng)用運(yùn)行的基本機(jī)制,本質(zhì)上說(shuō)就是利用固定數(shù)量的線程處理所有業(yè)務(wù)邏輯。由于線程數(shù)量可控,編碼時(shí)無(wú)需考慮線程安全,線程資源分配的等問(wèn)題。每個(gè)Vertx實(shí)例默認(rèn)維護(hù)的線程數(shù)量為2*CPU核數(shù)
- Worker Pool:執(zhí)行阻塞任務(wù)所使用的線程池,默認(rèn)線程數(shù)量為20
- Verticle:Vertx應(yīng)用中的基本部署單位,一般一個(gè)Vertx應(yīng)用包含一個(gè)或多個(gè)Verticle,不同verticle之間使用event bus進(jìn)行通信
- Event Bus:不同verticle間的通信工具
1.2. Vertx的特點(diǎn)
-
異步:
維基百科對(duì)event loop的定義
the event loop is a programming construct or design pattern that waits for and dispatches events or messages in a program(事件循環(huán)是一種架構(gòu)或設(shè)計(jì)模式,它等待并分發(fā)程序中的事件、消息)

Vertx使用event loop機(jī)制處理業(yè)務(wù)邏輯,這種架構(gòu)模式提高了系統(tǒng)資源利用率,可以確保處理主業(yè)務(wù)的線程不會(huì)被浪費(fèi)在等待I/O的結(jié)果上,但要做到這些,我們必須更改編碼風(fēng)格,將對(duì)I/O結(jié)果的處理邏輯用回調(diào)的形式一并傳遞給event loop,Vertx將在action1完成時(shí)主動(dòng)調(diào)用我們注冊(cè)的回調(diào)函數(shù)
我們的代碼將由之前的
result1 = action1()
action2(result1)
變?yōu)?/p>
action1(
result1 ->
action2(result1)
)
這種代碼結(jié)構(gòu)在Vertx項(xiàng)目里隨處可見(jiàn)。顯然,一旦邏輯變得復(fù)雜,多重函數(shù)的嵌套將導(dǎo)致回調(diào)地獄,Vertx為提供了Promise類解決這種問(wèn)題,通過(guò)傳遞Promise對(duì)象,我們可以以同步的方式處理異步的邏輯。
private Future<Void> action() {
Promise<void> promise = Promise.promise();
// (...)
return promise.future();
}
Vertx4.0承諾所有的異步API都將具有Promise返回值。另外,也可以使用Rxjava以流的方式處理數(shù)據(jù)
-
模塊化及通信的解耦
Vertx使用vertical劃分模塊,各模塊間只能通過(guò)event bus通信,而不是通過(guò)聚合等方式相互調(diào)用,這樣我們就不需擔(dān)心模塊間耦合。
event bus使用起來(lái)相當(dāng)簡(jiǎn)單,它使用Json作為的消息格式,我們僅需在消費(fèi)端定義監(jiān)聽地址(僅僅是一個(gè)字符串),在生產(chǎn)端指定消息發(fā)送地址即可,并且它有3種通信模式:
- 請(qǐng)求-響應(yīng):向目標(biāo)地址發(fā)送消息并由回調(diào)方法處理一個(gè)期待響應(yīng)結(jié)果
- 異步推送:直接發(fā)送一條信息,不期待響應(yīng)
- 廣播:當(dāng)多個(gè)verticle訂閱了相同的地址,以上兩種模式發(fā)送的消息只能被至多一個(gè)消費(fèi)者收到,而廣播模式可以向多個(gè)消費(fèi)者發(fā)送消息
當(dāng)event bus檢測(cè)到收發(fā)方均為本地模塊時(shí),他的底層僅僅會(huì)對(duì)數(shù)據(jù)做序列化和反序列化的操作,不會(huì)增加產(chǎn)生額外消耗。它甚至可以結(jié)合官方推出的其他組件(如TCP橋接、集群管理器等)很方便地實(shí)現(xiàn)跨進(jìn)程、跨設(shè)備的通信,這使得一個(gè)Vertx可以及其方便進(jìn)行橫向拓展
每個(gè)vertical默認(rèn)只使用event loop中的一個(gè)線程進(jìn)行運(yùn)算,所以模塊內(nèi)部的邏輯是高內(nèi)聚的,可以隨意使用全局變量而無(wú)需擔(dān)心線程安全問(wèn)題
“多線程”的event loop是Vertx的殺手锏,當(dāng)一個(gè)Vertx實(shí)例中的某個(gè)vertical負(fù)荷過(guò)大時(shí),我們可以在Vertx實(shí)例啟動(dòng)時(shí)直接指定此vertical的部署數(shù)量,充分利用CPU資源
2.響應(yīng)式編程
Don't call us,we'll call you.
響應(yīng)式的編程范式其實(shí)就是設(shè)計(jì)模式中“觀察者模式”的一種實(shí)踐
我們?cè)谠O(shè)計(jì)代碼結(jié)構(gòu)(或設(shè)計(jì)項(xiàng)目架構(gòu))時(shí),并不直接地針對(duì)某個(gè)具體業(yè)務(wù)給出方案,而是分析業(yè)務(wù)涉及到的各個(gè)角色,并對(duì)思考他們自身在項(xiàng)目中的地位以及他們之間的聯(lián)系,最后構(gòu)建出各個(gè)模塊
重點(diǎn)考慮模塊是如何與其他模塊達(dá)到松耦合的:
- 簡(jiǎn)單使用“觀察者模式”:那么在核心邏輯執(zhí)行前觀察者將自身的引用提供給目標(biāo)對(duì)象抽象(被觀察的主體),目標(biāo)對(duì)象維護(hù)一個(gè)觀察者列表,待自身特定事件發(fā)生時(shí),一次性通知所有的觀察者
- Vertx中的vertical僅僅使用evnet bus組件與其他模塊通信,并且對(duì)任何阻塞操作僅允許通過(guò)回調(diào)的方式執(zhí)行后續(xù)邏輯
構(gòu)建一套響應(yīng)式系統(tǒng)使得系統(tǒng)間各模塊協(xié)作更為自然,代碼健壯性更高
如果不使用第三方框架,單純自行設(shè)計(jì)這一套系統(tǒng)的成本是巨大的,僅考慮線程間的同步問(wèn)題就夠喝一壺的了,更不用說(shuō)如何去滿足業(yè)務(wù)需求
3.工具的使用
但是理想中完美的東西未必能在現(xiàn)實(shí)中發(fā)我們所預(yù)期作用
作為一個(gè)貫徹響應(yīng)式編程思維的工具集,Vertx提供了一整套完善的響應(yīng)式系統(tǒng),它對(duì)幾乎所有一般項(xiàng)目中的業(yè)務(wù)需求提供了解決方案,但它終究不是一個(gè)具有工程屬性的重量級(jí)框架,例如數(shù)據(jù)庫(kù)相關(guān)組件僅僅是在原生驅(qū)動(dòng)的基礎(chǔ)上提供了一層極薄封裝
需要做“規(guī)范化”的工程時(shí),使用這樣的工具集我們不免陷入“再造輪子”的困境,所以,在項(xiàng)目開始初期時(shí),需要結(jié)合多方面因素考慮,選擇適合項(xiàng)目的工具,以達(dá)到工具的“為我所用”的目的