Vert.x學(xué)習(xí)筆記(一) Vert.x 核心包

Vert.x是一個事件驅(qū)動的JVM上的框架乎串,可以幫助我們構(gòu)建現(xiàn)代、靈活速警、可擴(kuò)展的程序叹誉。Vert.x有多種語言的版本,可以用在Java闷旧、Kotlin长豁、Scala、Groovy忙灼、Ruby等語言上匠襟。當(dāng)然現(xiàn)在討論的是如何在Java上使用Vert.x。

Vert.x是一個比較大的框架该园,包含了各個方面的功能酸舍。所以我決定寫幾篇文章,分別來介紹這些功能里初。所以今天先來看看Vert.x最核心的一些功能吧啃勉,這些功能都在vertx-core包下。官方的英文文檔在這里青瀑,本文參考和引用了Vertx官方文檔上的一些內(nèi)容璧亮,如果需要詳細(xì)信息請直接看官方文檔萧诫。當(dāng)然我又發(fā)現(xiàn)了志愿者翻譯的中文文檔,質(zhì)量也可以枝嘶,只不過版本稍微落后一些帘饶。

Vert.x核心庫包含了以下一些功能,它們都是比較底層的功能群扶,開發(fā)者可以根據(jù)需要使用及刻。當(dāng)然由于Vert.x的功能很多,所以這里我不打算全部介紹竞阐,只準(zhǔn)備介紹一些比較常用的功能缴饭。如果想了解全部功能的話,還是請參考官方文檔骆莹。

  • TCP客戶端和服務(wù)端
  • HTTP客戶端和服務(wù)端以及WebSockets支持
  • 事件總線
  • 共享數(shù)據(jù)颗搂,包括本地maps以及分布式聚簇maps
  • 周期性和延遲操作
  • 數(shù)據(jù)報
  • DNS客戶端
  • 文件系統(tǒng)訪問
  • 高可用性
  • 聚簇

Vert.x的特點(diǎn)是事件驅(qū)動、流式編程和非阻塞幕垦,這些特點(diǎn)將會在后面逐一介紹丢氢。

引入依賴

如果使用Maven的話,在pom.xml中添加以下一段即可先改。

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-core</artifactId>
  <version>3.4.2</version>
</dependency>

如果使用Gradle的話疚察,在build.gradle中添加以下一段。

dependencies {
  compile 'io.vertx:vertx-core:3.4.2'
}

開始使用

創(chuàng)建Vertx對象

要使用Vertx的第一步就是創(chuàng)建Vertx對象仇奶,所有API都要通過這個對象來調(diào)用貌嫡。一般情況下,一個程序只需要一個Vertx對象即可该溯,不過有時候為了程序隔離等原因岛抄,我們會需要多個Vertx對象。創(chuàng)建Vertx對象很簡單朗伶,調(diào)用下面一行代碼即可弦撩。

Vertx vertx = Vertx.vertx();

有時候可能需要對Vertx進(jìn)行一些配置步咪,可以通過添加程序參數(shù)來實現(xiàn)论皆。

VertxOptions options = new VertxOptions();
options.setWorkerPoolSize(20);
Vertx vertx2 = Vertx.vertx(options);

Verticles

Verticles是Vertx中的一個模型,可以幫助我們封裝代碼猾漫。Verticles是一個可選的模型点晴,所以即使我們不使用Verticles,也可以繼續(xù)使用Vertx悯周。Verticles說起來很簡單粒督,就是一個接口。當(dāng)然實際情況下禽翼,一般都是繼承AbstractVerticle抽象類屠橄。

public abstract class AbstractVerticle implements Verticle {

  protected Vertx vertx;

  protected Context context;
  @Override
  public Vertx getVertx() {
    return vertx;
  }
  @Override
  public void init(Vertx vertx, Context context) {
    this.vertx = vertx;
    this.context = context;
  }

  public String deploymentID() {
    return context.deploymentID();
  }
  public JsonObject config() {
    return context.config();
  }
  public List<String> processArgs() {
    return context.processArgs();
  }
  @Override
  public void start(Future<Void> startFuture) throws Exception {
    start();
    startFuture.complete();
  }
  @Override
  public void stop(Future<Void> stopFuture) throws Exception {
    stop();
    stopFuture.complete();
  }
  public void start() throws Exception {
  }
  public void stop() throws Exception {
  }

}

繼承AbstractVerticle抽象類之后族跛,必須實現(xiàn)的方法是start(),它會在Verticle部署的時候調(diào)用锐墙,還有一個可選的方法stop()礁哄,在Verticle停止的時候調(diào)用。

public class MyVerticle extends AbstractVerticle {

  // Called when verticle is deployed
  public void start() {
  }

  // Optional - called when verticle is undeployed
  public void stop() {
  }

}

如果需要異步Verticle溪北,繼承并實現(xiàn)方法簽名帶有Future的那幾個方法即可桐绒。

使用JSON

Java中沒有對JSON的原生支持,所以Vertx首先就對這些數(shù)據(jù)類型進(jìn)行了支持之拨。

JSON對象

首先先來看看JSON對象茉继。我們可以由字符串創(chuàng)建JSON對象。

String jsonString = "{\"name\":\"yitian\",\"age\":25}";
JsonObject jsonObject = new JsonObject(jsonString);
System.out.println(jsonObject);

也可以由Map來創(chuàng)建Json對象蚀乔。

Map<String, Object> map = new HashMap<>();
map.put("name", "yitian");
map.put("age", 25);
JsonObject jsonObject2 = new JsonObject(map);
System.out.println(jsonObject2);

當(dāng)然也可以直接創(chuàng)建JsonObj對象烁竭。JsonObject的默認(rèn)構(gòu)造函數(shù)會創(chuàng)建一個空J(rèn)son對象,然后我們可以向其中填充數(shù)據(jù)吉挣。這個對象支持流式操作颖变,所以可以直接把多個put方法連續(xù)調(diào)用。

JsonObject jsonObject3 = new JsonObject();
jsonObject3.put("name", "yitian").put("age", 25);
System.out.println(jsonObject3);

如果要獲取Json對象的屬性值也很簡單听想,調(diào)用相應(yīng)的getXXX方法即可腥刹。

String name = jsonObject.getString("name");
int age = jsonObject.getInteger("age");
System.out.printf("name:%s,age:%d", name, age);

Json對象也可以和Java實體類之間通過mapTomapFrom互轉(zhuǎn)。

User user = jsonObject.mapTo(User.class);
System.out.println(user);
JsonObject userObject = JsonObject.mapFrom(user);
System.out.println(userObject);

最后汉买,Json對象也可以轉(zhuǎn)換為字符串衔峰,只需要調(diào)用encode方法即可。如果查看源代碼可以發(fā)現(xiàn)JsonObjecttoString方法也調(diào)用了encode方法蛙粘,所以通過toString方法也可以轉(zhuǎn)為字符串(不過有點(diǎn)多此一舉的意思)垫卤。

String stringValue = jsonObject.encode();
System.out.println(stringValue);

JSON數(shù)組

如果要創(chuàng)建Json數(shù)組,使用JsonArray類出牧。它的使用方法和JsonObject類似穴肘。

JsonArray jsonArray = new JsonArray();
jsonArray.add("yitian").add(25).add(true);
System.out.println(jsonArray);
System.out.println(jsonArray.encode());

//獲取Json數(shù)組的元素
String name = jsonArray.getString(0);
int age = jsonArray.getInteger(1);
System.out.printf("name:%s,age:%d", name, age);

Buffer

Buffer是Vertx中通用的一種傳遞數(shù)據(jù)的方式,所以先來介紹一下它舔痕。

創(chuàng)建Buffer

有以下幾種創(chuàng)建Buffer的方式评抚。如果預(yù)先知道需要數(shù)據(jù)的大小,可以使用最后一種方式伯复,在創(chuàng)建的同時指定Buffer的大小慨代。

//創(chuàng)建空Buffer
Buffer buffer1 = Buffer.buffer();
Buffer buffer2 = Buffer.buffer(new byte[]{1, 2, 3, 4, 5});
Buffer buffer3 = Buffer.buffer("abcde");
Buffer buffer4 = Buffer.buffer("一二三四五", "utf-8");
//創(chuàng)建帶初始大小的Buffer
Buffer buffer5 = Buffer.buffer(1024);

寫入Buffer

有兩種寫入Buffer的方式,追加寫入(appendXXX)和隨機(jī)寫入(setXXX)啸如,這些方法對于各種常用類型做了重載侍匙,可以滿足我們各種需求。顧名思義叮雳,追加寫入會將數(shù)據(jù)寫入Buffer的最后想暗;隨機(jī)寫入可以修改Buffer任何位置的數(shù)據(jù)妇汗。Buffer可以自動擴(kuò)容,所以不必?fù)?dān)心出現(xiàn)IndexOutOfBoundsException说莫。

Buffer buffer = Buffer.buffer();
//追加寫入方式
buffer.appendString("some text");
//隨機(jī)寫入方式
buffer.setString(10, "abcde");

讀取Buffer

從Buffer讀取數(shù)據(jù)使用getXXX方法即可铛纬。

//讀取數(shù)據(jù)
for (int i = 0; i < buffer.length(); ++i) {
    System.out.print(buffer.getShort(i));
}

當(dāng)把Buffer提交到網(wǎng)絡(luò)套接字等目的地后,Buffer就不能被重用了唬滑。

TCP服務(wù)端和客戶端

TCP服務(wù)端

首先需要使用Vertx對象創(chuàng)建一個TCP服務(wù)器告唆。

NetServer server = vertx.createNetServer();

如果需要配置服務(wù)器的屬性,可以在創(chuàng)建的時候傳遞一個NetServerOptions類型參數(shù)晶密。

NetServerOptions options = new NetServerOptions().setPort(4321);
NetServer server = vertx.createNetServer(options);

要讓服務(wù)器開始監(jiān)聽擒悬,使用下面代碼即可。

NetServer server = vertx.createNetServer();
server.listen();

當(dāng)然也可以在監(jiān)聽的時候指定端口號等屬性稻艰,這時候會覆蓋前面設(shè)置的NetServerOptions屬性懂牧。默認(rèn)地址是0.0.0.0,表示監(jiān)聽所有可用的地址尊勿,默認(rèn)端口號是0僧凤,表示隨機(jī)選取一個可用的端口號。

NetServer server = vertx.createNetServer();
server.listen(1234, "localhost");

如果希望及時獲取服務(wù)器監(jiān)聽的結(jié)果元扔,可以使用下面的形式躯保,通過lambda表達(dá)式來及時得知監(jiān)聽成功與否。

NetServer server = vertx.createNetServer();
server.listen(1234, "localhost", res -> {
  if (res.succeeded()) {
    System.out.println("Server is now listening!");
  } else {
    System.out.println("Failed to bind!");
  }
});

如果使用隨機(jī)端口號澎语,那么需要在監(jiān)聽成功之后獲取TCP服務(wù)器使用的端口號途事。

NetServer server = vertx.createNetServer();
server.listen(0, "localhost", res -> {
  if (res.succeeded()) {
    System.out.println("Server is now listening on actual port: " + server.actualPort());
  } else {
    System.out.println("Failed to bind!");
  }
});

如果要從套接字獲取數(shù)據(jù),需要以下的代碼擅羞。

NetServer server = vertx.createNetServer();
server.connectHandler(socket -> {
  socket.handler(buffer -> {
    System.out.println("I received some bytes: " + buffer.length());
  });
});

如果要向套接字獲取寫入數(shù)據(jù)尸变,可以利用前面介紹的Buffer。需要注意减俏,一旦將Buffer寫入套接字召烂,那么Buffer將會失效,無法重用娃承。

Buffer buffer = Buffer.buffer().appendFloat(12.34f).appendInt(123);
socket.write(buffer);

// Write a string in UTF-8 encoding
socket.write("some data");

// Write a string using the specified encoding
socket.write("some data", "UTF-16");

最后奏夫,要關(guān)閉服務(wù)器,調(diào)用close方法草慧。當(dāng)然也可以檢查關(guān)閉結(jié)果桶蛔。

server.close(res -> {
  if (res.succeeded()) {
    System.out.println("Server is now closed");
  } else {
    System.out.println("close failed");
  }
});

前面我們使用了connectHandler來讀取套接字傳遞來的數(shù)據(jù)匙头,當(dāng)然還有幾個Handler可供使用漫谷。closeHandler在服務(wù)器關(guān)閉的時候通知我們,而exceptionHandler會將所有異常報告給我們蹂析。

TCP客戶端

要創(chuàng)建TCP客戶端很簡單舔示。

NetClient client = vertx.createNetClient();

類似地碟婆,也可以在創(chuàng)建的時候指定配置。

NetClientOptions options = new NetClientOptions().setConnectTimeout(10000);
NetClient client = vertx.createNetClient(options);

創(chuàng)建客戶端之后惕稻,需要和服務(wù)器進(jìn)行連接竖共。

NetClientOptions options = new NetClientOptions().setConnectTimeout(10000);
NetClient client = vertx.createNetClient(options);
client.connect(4321, "localhost", res -> {
  if (res.succeeded()) {
    System.out.println("Connected!");
    //用Socket操作數(shù)據(jù)
    NetSocket socket = res.result();
  } else {
    System.out.println("Failed to connect: " + res.cause().getMessage());
  }
});

HTTP服務(wù)器和客戶端

HTTP服務(wù)器

創(chuàng)建HTTP服務(wù)器很簡單。

HttpServer server = vertx.createHttpServer();

如果需要指定配置俺祠,也很容易公给。

HttpServerOptions options = new HttpServerOptions().setMaxWebsocketFrameSize(1000000);

HttpServer server = vertx.createHttpServer(options);

創(chuàng)建服務(wù)器之后,還需要監(jiān)聽端口蜘渣。默認(rèn)地址是0.0.0.0淌铐,默認(rèn)端口號是80

HttpServer server = vertx.createHttpServer();
server.listen();

//監(jiān)聽指定端口
server.listen(8080, "myhost.com");

如果要確定是否監(jiān)聽成功蔫缸,可以使用下面的代碼腿准。

HttpServer server = vertx.createHttpServer();
server.listen(8080, "myhost.com", res -> {
  if (res.succeeded()) {
    System.out.println("Server is now listening!");
  } else {
    System.out.println("Failed to bind!");
  }
});

要處理發(fā)送過來的HTTP請求,使用requestHandler拾碌。Handler內(nèi)部的request參數(shù)有很多屬性和方法可以幫助我們獲取相應(yīng)的數(shù)據(jù)吐葱。熟悉Java Servlet編程的同學(xué)應(yīng)該會感到很親切。這里就不詳細(xì)介紹了校翔。

server.requestHandler(request -> {
  // 在這里編寫代碼
});

要返回響應(yīng)弟跑,需要Response對象。

HttpServerResponse response = request.response();
response.write(buffer);
//直接返回字符串也可以
response.write("hello world!");
//輸出完響應(yīng)之后需要關(guān)閉相應(yīng)流
response.end();

如果要指定返回的header防症、content-type等信息窖认,可以用下面的代碼。

HttpServerResponse response = request.response();
MultiMap headers = response.headers();
headers.set("content-type", "text/html");
headers.set("other-header", "wibble");

或者直接使用putHeaders方法告希。

response.putHeader("content-type", "text/html").putHeader("other-header", "wibble");

Vertx還有一些特性扑浸,可以幫助我們處理文件上傳等情況,不過篇幅所限就不介紹了燕偶。

HTTP客戶端

要創(chuàng)建HTTP客戶端很簡單喝噪。

HttpClient client = vertx.createHttpClient();

如果要增加配置,可以這樣指么。

HttpClientOptions options = new HttpClientOptions().setKeepAlive(false);
HttpClient client = vertx.createHttpClient(options);

如果要發(fā)起請求酝惧,調(diào)用客戶端的相應(yīng)方法即可。

Vertx vertx = Vertx.vertx();
HttpClient client = vertx.createHttpClient();
client.getNow("httpbin.org", "/get", response -> {
    response.bodyHandler(System.out::println);
});

由于篇幅所限伯诬,這里只介紹Vert.x 核心包的一些功能晚唇,如果想了解更多信息,請直接查看官方文檔盗似。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哩陕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌悍及,老刑警劉巖闽瓢,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異心赶,居然都是意外死亡扣讼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門缨叫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椭符,“玉大人,你說我怎么就攤上這事耻姥〖枭剑” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵咏闪,是天一觀的道長曙搬。 經(jīng)常有香客問我,道長鸽嫂,這世上最難降的妖魔是什么纵装? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮据某,結(jié)果婚禮上橡娄,老公的妹妹穿的比我還像新娘。我一直安慰自己癣籽,他們只是感情好挽唉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著筷狼,像睡著了一般瓶籽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上埂材,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天塑顺,我揣著相機(jī)與錄音,去河邊找鬼俏险。 笑死严拒,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的竖独。 我是一名探鬼主播裤唠,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼莹痢!你這毒婦竟也來了种蘸?” 一聲冷哼從身側(cè)響起墓赴,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎劈彪,沒想到半個月后竣蹦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體顶猜,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沧奴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了长窄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滔吠。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖挠日,靈堂內(nèi)的尸體忽然破棺而出疮绷,到底是詐尸還是另有隱情,我是刑警寧澤嚣潜,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布冬骚,位于F島的核電站,受9級特大地震影響懂算,放射性物質(zhì)發(fā)生泄漏只冻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一计技、第九天 我趴在偏房一處隱蔽的房頂上張望喜德。 院中可真熱鬧,春花似錦垮媒、人聲如沸舍悯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萌衬。三九已至,卻和暖如春它抱,著一層夾襖步出監(jiān)牢的瞬間奄薇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工抗愁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留馁蒂,地道東北人。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓蜘腌,卻偏偏與公主長得像沫屡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子撮珠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容