摘要:主要是避免引入太多的復(fù)雜性,并且出于靈活部署的需要。以應(yīng)用為例,由于實(shí)際上是在上執(zhí)行,若它被阻塞,即導(dǎo)致后續(xù)請(qǐng)求全部無(wú)法得到處理。因此,最合適的做法就是對(duì)于簡(jiǎn)單業(yè)務(wù),采用異步庫(kù)。本系列其他文章入坑須知入坑須知入坑須知
最開(kāi)始覺(jué)得這個(gè)系列也就最多3篇了不起了(因?yàn)槭虏贿^(guò)三嘛),沒(méi)曾想居然迎來(lái)了第四篇!
Kotlin由于最近決定投身到區(qū)塊鏈的學(xué)習(xí)當(dāng)中的緣故,出于更好的理解它的基本概念,自己動(dòng)手參考文章寫(xiě)了一個(gè)迷你區(qū)塊鏈的例子。采用了kotlin + vertx的工具選擇。這次嘗試再次驗(yàn)證了我在本系列一開(kāi)篇所說(shuō):建議以Java語(yǔ)言開(kāi)發(fā)為主。原因很簡(jiǎn)單,因?yàn)檫@個(gè)是基礎(chǔ),所以各方面支持(包括文檔和功能方面)肯定是Java語(yǔ)言優(yōu)先。
在做這個(gè)區(qū)塊鏈的例子時(shí),Vertx Kotlin的文檔讓我有極為糟糕的體驗(yàn):從整篇文檔中,你找不到一個(gè)完整的用kotlin書(shū)寫(xiě)Verticle的例子,閱讀的時(shí)候就感覺(jué)內(nèi)容有跳躍。雖然你可以猜出應(yīng)該是繼承AbstractVerticle,但你肯定還是希望文檔中明確指出來(lái)。
當(dāng)然啦,盡管有這樣的問(wèn)題,寫(xiě)代碼的體驗(yàn)還是不錯(cuò)的。就build.gradle而言,跟Java + Groovy組合的差別不大。唯一需要注意的是,你可能需要將kotlin的jvmTarget設(shè)置為“1.8”。具體的配置可以參考工程的build.gradle。
總之,發(fā)現(xiàn)文檔有問(wèn)題,就先查Java文檔。
靜態(tài)資源上面的區(qū)塊鏈的例子由兩部分組成:前端靜態(tài)頁(yè)面 + 后端的Verticle,前端靜態(tài)頁(yè)面通過(guò)Ajax請(qǐng)求與后端的Verticle交互。這其實(shí)就是通過(guò)Vertx-Web的StaticHandler來(lái)實(shí)現(xiàn)的,很簡(jiǎn)單。這里只提兩個(gè)需要留心的小地方。
首先,靜態(tài)資源的根路徑默認(rèn)情況下是:src/main/resources/webroot。即當(dāng)你請(qǐng)求“http://localhost:8080/index.html”時(shí),其實(shí)對(duì)應(yīng)的是:src/main/resources/webroot/index.html。
其次,目前的Web應(yīng)用的URL很少會(huì)直接出現(xiàn)“……/xxx.html”。按照向Spring MVC或Grails這里框架的做法,一般是經(jīng)過(guò)一個(gè)action,然后將瀏覽器導(dǎo)向某個(gè)頁(yè)面。在做這個(gè)例子時(shí),其實(shí)沒(méi)有這么復(fù)雜的邏輯,讓瀏覽器直接去加載某個(gè)頁(yè)面(如configure.html)就可以了。但這樣會(huì)出現(xiàn)一個(gè)讓人很不爽的Path:“/configure.html”,而其他的路徑因?yàn)橹饕秦?fù)責(zé)處理Ajax請(qǐng)求,都是形如“/mine”這樣的路徑。
為了統(tǒng)一路徑風(fēng)格,這里采用了一個(gè)小技巧:RoutingContext.reroute。參考代碼如下:
router.get("/configure").handler({ rc: RoutingContext -> rc.reroute("/configure.html") })JDBC連接池
Vert.x JDBC client缺省的連接池提供者是c3p0,但它也支持其他其他的連接池,比如大名鼎鼎的Hikari。但遺憾的是,文檔中沒(méi)有給出一個(gè)完整的代碼示例。對(duì)于想換用其他連接池的同學(xué),可以參考下面的代碼:
JDBCClient.createShared(vertx, new JsonObject() .put("provider_class", "io.vertx.ext.jdbc.spi.impl.HikariCPDataSourceProvider") .put("driverClassName", "org.postgresql.Driver") .put("jdbcUrl", jdbcUrl) .put("username", username) .put("password", password) .put("maximumPoolSize", maximumPoolSize) .put("minimumIdle", minimumIdle) .put("cachePrepStmts", true) .put("prepStmtCacheSize", 250) .put("prepStmtCacheSqlLimit", 2048));
對(duì)于用Postgresql的同學(xué),還可以看看Reactive Postgres Client,一個(gè)高性能的輕量級(jí)jdbc client同時(shí)自帶連接池,作者也是vertx的貢獻(xiàn)者。
回調(diào)的線程安全性使用Vert.x的最大好處就是極大簡(jiǎn)化了多線程編程的復(fù)雜性,大部分時(shí)候你幾乎不需要去操心,這部分內(nèi)容分別在文檔的Standard verticles和Worker verticles有描述。
但文檔中并沒(méi)有專門(mén)闡述這一原則是否對(duì)于回調(diào)函數(shù)也適用,畢竟回調(diào)函數(shù)執(zhí)行的時(shí)機(jī)不確定并且典型的Vert.x程序充斥著回調(diào)。對(duì)于這個(gè)問(wèn)題,簡(jiǎn)單地說(shuō):同樣適用。下面的示例代碼可以驗(yàn)證這一點(diǎn):
public class Vert1 extends AbstractVerticle { long count = 0; @Override public void start() { HttpClient httpClient = vertx.createHttpClient(); for (int i = 0; i < 20; i++) { httpClient.getAbs("http://www.baidu.com/", response -> { count++; System.out.println(count); }).end(); } } }
從輸出來(lái)看,完全正確。作為對(duì)比,你可以在groovyConsole中運(yùn)行下面的代碼(多按幾次ctrl - r):
int count = 0 def c = { 10.times { count++ println count } } def t1 = new Thread(c) def t2 = new Thread(c) t1.start() t2.start()
并且,通過(guò)調(diào)研Vert.x源代碼,你可以(在HttpClientRequestBase中)發(fā)現(xiàn):
void handleResponse(HttpClientResponseImpl resp) { synchronized (getLock()) { // If an exception occurred (e.g. a timeout fired) we won"t receive the response. if (exceptionOccurred == null) { long timeoutMS = currentTimeoutMs; cancelOutstandingTimeoutTimer(); try { doHandleResponse(resp, timeoutMS); } catch (Throwable t) { handleException(t); } } } }
很明顯,Vert.x內(nèi)部已經(jīng)為你提前預(yù)防了,這就是框架的力量!如果你還在用Netty,不妨考慮Vert.x這個(gè)建構(gòu)于它之上的高層工具吧。
Unmount SubroutersSubrouter是個(gè)好東東,可API設(shè)計(jì)有個(gè)問(wèn)題:只有mount,沒(méi)有unmount!一般情況下,unmount的確用不上,但你一旦想實(shí)現(xiàn)動(dòng)態(tài)路由時(shí),它就是萬(wàn)萬(wàn)不可缺少的了。
好在我自己摸索出了下面的方法:
public static void unMountSubRouter(Router router, String root) { router.getRoutes().stream() .filter(route -> route.getPath() != null && route.getPath().startsWith(root)) .forEach(route -> route.remove()); }
有趣的是,Vert.x的開(kāi)發(fā)者曾經(jīng)覺(jué)得subrouter用處不大,并動(dòng)了把它在未來(lái)拿掉的念頭。當(dāng)這個(gè)想法被提出來(lái)征求社區(qū)意見(jiàn)時(shí),立馬有人跳出來(lái)說(shuō):“subrouter的設(shè)計(jì)非常好,哥的程序嚴(yán)重依賴它,請(qǐng)繼續(xù)保留。”
應(yīng)用架構(gòu)我曾經(jīng)不止一次看到初學(xué)者在問(wèn)類似這樣的問(wèn)題:
應(yīng)該創(chuàng)建多少Verticle實(shí)例?
Vert.x的應(yīng)用該怎么去設(shè)計(jì)?
怎么跟現(xiàn)有的框架結(jié)合?
……
要回答這些問(wèn)題,需要首先搞清楚幾個(gè)事實(shí)。
不要將Verticle和Thread混為一談,它們不是一類東西。簡(jiǎn)單的說(shuō),可以這樣理解:Verticle由Thread來(lái)執(zhí)行。
Vert.x中的Verticle由種類之分,不同類型的Verticle適用于不同場(chǎng)景,這一點(diǎn)在文檔中已經(jīng)有詳細(xì)的闡述。
Vert.x本身是一個(gè)庫(kù),并不妨礙它跟其他框架(如Grails)的結(jié)合。只不過(guò)就我個(gè)人而言,更偏好將Vert.x應(yīng)用多帶帶使用。主要是避免引入太多的復(fù)雜性,并且出于靈活部署的需要。
并且,通過(guò)觀察其他人寫(xiě)的Vert.x代碼(包括Vert.x自己的那些子項(xiàng)目),可以總結(jié)出來(lái)幾個(gè)套路。
Master - Worker這是最常見(jiàn)的結(jié)構(gòu):
標(biāo)準(zhǔn)Verticle,負(fù)責(zé)接收外部請(qǐng)求,完成請(qǐng)求分派和結(jié)果收集
Worker Verticle,負(fù)責(zé)臟活累活
標(biāo)準(zhǔn)Verticle和Worker Verticle之間通過(guò)eventbus進(jìn)行交互,整個(gè)架構(gòu)其實(shí)也很簡(jiǎn)單:
request <---> standard verticles <---> worker verticle
這里的一個(gè)典型反模式,尤其是初學(xué)者會(huì)大概率犯的錯(cuò)誤:將本該worker干的活,交給了標(biāo)準(zhǔn)verticle,即將圖中后兩個(gè)組件合二為一。這種情況在寫(xiě)Vertx Web時(shí)非常容易出現(xiàn),尤其受傳統(tǒng)MVC框架的影響,無(wú)意識(shí)地將原來(lái)的編程套路給照搬過(guò)來(lái)了:在Handler中進(jìn)行了大量操作。我自己也不例外,走過(guò)這段彎路。
Don"t block me!
以Vert.x Web應(yīng)用為例,由于Handler實(shí)際上是在eventloop上執(zhí)行,若它被阻塞,即導(dǎo)致后續(xù)請(qǐng)求全部無(wú)法得到處理。因此,最合適的做法就是:
對(duì)于簡(jiǎn)單業(yè)務(wù),采用異步庫(kù)。
對(duì)于復(fù)雜業(yè)務(wù),干脆交給worker去處理。
異步工具庫(kù)利用Vert.x的特點(diǎn),將IO操作封裝成異步庫(kù)。
微服務(wù)用Vert.x將業(yè)務(wù)功能封裝成微服務(wù),然后利用現(xiàn)成的基礎(chǔ)設(shè)施與其他應(yīng)用交互:
利用kafka隊(duì)列實(shí)現(xiàn)服務(wù)間的交互
利用TCP Bridge實(shí)現(xiàn)與tcp client的交互
利用Eventbus Bridge實(shí)現(xiàn)與頁(yè)面的交互
利用數(shù)據(jù)庫(kù)實(shí)現(xiàn)與應(yīng)用的簡(jiǎn)單交互
……
這也是我最喜歡用的模式,輕量,簡(jiǎn)單,部署方便。我不太喜歡在一個(gè)本來(lái)就已經(jīng)含有復(fù)雜業(yè)務(wù)邏輯的Grails應(yīng)用中再包含一個(gè)Vert.x Verticle了。
或許有同學(xué)對(duì)于上面的最后一項(xiàng),感到疑惑。其實(shí)這個(gè)很簡(jiǎn)單,以Postgresql為例,可以采用兩種模式:
簡(jiǎn)單的“定時(shí)任務(wù)+表”的方式,通過(guò)表的某個(gè)字段實(shí)現(xiàn)服務(wù)間的集成
利用PG自身支持的pub/sub功能
行了,本篇寫(xiě)到這里也差不多了。最后給大家推薦一個(gè)網(wǎng)頁(yè):Awesome Vert.x,上面有不少不錯(cuò)的資源。
本系列其他文章:
Vert.x入坑須知(1)
Vert.x入坑須知(2)
Vert.x入坑須知(3)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/69249.html
摘要:對(duì)于集成測(cè)試,直接模擬實(shí)際的環(huán)境,再加上合適的,目前看來(lái)也還不錯(cuò)。這里給出兩個(gè)例子集成測(cè)試單元測(cè)試都是基于寫(xiě)的,各位可以體驗(yàn)其酸爽度。好啦,本期內(nèi)容就此結(jié)束,請(qǐng)保持關(guān)注,期待下期繼續(xù)本系列其他文章入坑須知入坑須知 隨著Vert.x進(jìn)化到3.5.0,本系列也迎來(lái)了新篇章。 CORS的新變化 對(duì)于CORS,搞Web開(kāi)發(fā)(不論你是前端,還是后端)的同志應(yīng)該不陌生,尤其是如今微服務(wù)盛行的時(shí)代,...
摘要:輕量級(jí),部署簡(jiǎn)單。此外,本文也不是入門(mén)文檔,而是為了預(yù)防陷坑而給出的指導(dǎo)意見(jiàn),故在閱讀本文之前還請(qǐng)先仔細(xì)閱讀的文檔??梢曌鞯囊粋€(gè)最小部署和運(yùn)行單元,簡(jiǎn)單的說(shuō),可類比為。,主,負(fù)責(zé)部署程序中其他的。嚴(yán)格來(lái)講,之后,上述第一點(diǎn)并不完全正確。 一直以來(lái)早有將這些年用Vert.x的經(jīng)驗(yàn)整理一下的想法,奈何天生不是勤快人,直到最近扶墻老師問(wèn)起,遂成此文。 選擇理由 現(xiàn)在想想,我們應(yīng)該算是國(guó)內(nèi)用V...
摘要:這一點(diǎn)其實(shí)是非常不妥的,有潛在的安全問(wèn)題。這次,在項(xiàng)目中終于采用了以它為基礎(chǔ)的集群方案。相反,使用一個(gè)周期,但針對(duì)每個(gè)生成一個(gè)一次性的,模擬隨機(jī)發(fā)送。同時(shí),要記得用完之后立即釋放。 當(dāng)初創(chuàng)建簡(jiǎn)書(shū)賬號(hào)的時(shí)候曾立下宏愿,希望保持周更,無(wú)奈現(xiàn)實(shí)殘酷,整個(gè)5月都處于忙忙碌碌的狀態(tài),居然令這個(gè)本來(lái)并不算太宏偉的目標(biāo)難以為繼,最終導(dǎo)致5月份交了白卷!【好吧,我承認(rèn),是我意志不夠堅(jiān)定,太懶了,;)】...
摘要:而不是開(kāi)始,將服務(wù)使用多線程的請(qǐng)求重量級(jí)的容器。是啟動(dòng)多個(gè)輕便單線程的服務(wù)器和流量路由到他們。亮點(diǎn)應(yīng)用程序是事件驅(qū)動(dòng),異步和單線程的。通過(guò)使用事件總線傳遞消息通信。為了建立一個(gè)消息系統(tǒng),則需要獲得該事件總線。 摘要 如果你對(duì)Node.js感興趣,Vert.x可能是你的下一個(gè)大事件:一個(gè)建立在JVM上一個(gè)類似的架構(gòu)企業(yè)制度。 這一部分介紹Vert.x是通過(guò)兩個(gè)動(dòng)手的例子(基于Vert.x...
摘要:上部分藍(lán)圖教程中我們一起探索了如何用開(kāi)發(fā)一個(gè)基于消息的應(yīng)用。對(duì)部分來(lái)說(shuō),如果看過(guò)我們之前的藍(lán)圖待辦事項(xiàng)服務(wù)開(kāi)發(fā)教程的話,你應(yīng)該對(duì)這一部分非常熟悉了,因此這里我們就不詳細(xì)解釋了。有關(guān)使用實(shí)現(xiàn)的教程可參考藍(lán)圖待辦事項(xiàng)服務(wù)開(kāi)發(fā)教程。 上部分藍(lán)圖教程中我們一起探索了如何用Vert.x開(kāi)發(fā)一個(gè)基于消息的應(yīng)用。在這部分教程中,我們將粗略地探索一下kue-http模塊的實(shí)現(xiàn)。 Vert.x Kue ...
閱讀 1150·2021-11-16 11:44
閱讀 1416·2019-08-30 13:12
閱讀 2471·2019-08-29 16:05
閱讀 3136·2019-08-28 18:29
閱讀 952·2019-08-26 13:41
閱讀 3280·2019-08-26 13:34
閱讀 2659·2019-08-26 10:35
閱讀 987·2019-08-26 10:28