Vert.x 3学习笔记---01

时间:2021-04-14 18:01:49

Vert.x 3 core:

Vert.x core主要提供了一下功能:

  • Writing TCP clients and servers(TCP 客户端和服务端)
  • Writing HTTP clients and servers including support for WebSockets(HTTP客户端和服务端,提供WebSocket的支持)
  • The Event bus(事件总线)
  • Shared data - local maps and clustered distributed maps(共享数据,本地map和集群map)
  • Periodic and delayed actions(定期和延迟的动作)
  • Deploying and undeploying Verticles(部署和卸载Verticles)
  • Datagram Sockets(数据报)
  • DNS client
  • File system access
  • High availability(高可用)
  • Clustering(可集群化)

Vert.x 3提供多种语言编程,支持java、ruby、goovy、JavaScript、Ceylon。提供了原生的API支持。

Maven (in your pom.xml):

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

Gradle (in your build.gradle file):

compile io.vertx:vertx-core:3.2.1

1. 从vertx对象开始:

Vertx vertx = Vertx.vertx();

你可以直接使用以上代码获取vertx对象,以便能很便捷的使用。不过我们大多数的app只是单个的vertx对象,再一些特殊情况下可能使用多个,例如:事件总线或者多个服务端或者多个客户端之间。

创建vertx对象还可以使用一些参数来创建:

Vertx vertx = Vertx.vertx( new VertxOptions().setWorkerPoolSize(40) );

VertxOptions对象就是包含这些设置参数的对象。

2. Don’t call us, we’ll call you.(一个很著名的模式)

vert.x是事件驱动的,当有你感兴趣的事件产生时,vert.x会调用你(异步)。举个例子,你可以接收一个时间(每秒的)事件:

vertx.setPeriodic(1000, id -> {
// This handler will get called every second
System.out.println("timer fired!");
});

或者接收一个http的请求:

server.requestHandler(request -> {
// This handler will be called every time an HTTP request is received at the server
request.response().end("hello world!");
});

不要阻塞

在Vert.x中只有很少的地方会进行阻塞操作,例如同步操作下的文件系统操作。
如果(请求的)结果能够很迅速的得到,那么就快速的返回结果就可以了。否则的话,你需要提供一个handler(回调)来监听一些事件。因为Vert.x的api不会去阻塞线程,因此你可以使用很少的线程来达到一些同步的操作。
当然也会有一些很方便的同步操作会阻塞线程,例如:从socket读取数据,向磁盘写入数据,向一个容器发送数据并等待返回,等等。

Reactor and Multi-Reactor

大多数的情况下,Vert.x通过一个叫event-loop的线程来调用咱们的handler(回调)。因为没有阻塞,event-loop线程在很短的事件里,会交付巨量的handler回调。
标准的Reactor实现,是基于单例的event-loop线程。而这会带来一定程度的困扰。因为一次只能运行一个,因此如果需要扩展的话,你就不得不启动和管理多个不同的进程。
Vert.x在这一点上的实现有所不同。一个vert.x对象包含了多个event-loop实例。默认情况下,Vert.x选择了基于机器可用内核的数量,但我们是可以改变的。这也就意味着一个Vert.x对象可以扩展(across your server),这一点上是node.js不能比拟的。
我们称这种模式叫Multi-Reactor Pattern

The Golden Rule - Don’t Block the Event Loop

(黄金法则:不要阻塞event-loop线程)

Running blocking code

在讨论之前,我们不应该直接的在event-loop线程中调用阻塞代码。如果这样的话,将会导致之前的代码不能工作。
我们可以通过executeBlocking 来执行同步的代码。

vertx.executeBlocking(future -> {
// Call some blocking API that takes a significant amount of time to return
String result = someAPI.blockingMethod("hello");
future.complete(result);
}, res -> {
System.out.println("The result is: " + res.result());
});

当在同一个context下(如同一个vertical中)执行了非常多的executeBlocking,这些executeBlocking会排队按顺序执行。但是如果你不关心这些executeBlocking执行的顺序,那么你可以设置executeBlocking的参数ordered为false。这样的话所有的executeBlocking代码就会并行的在工作线程中执行。
还有一种替代方案:将所有的阻塞代码作为一个worker verticle(见后面章节)

Async coordination 异步协调

通过Vert.x 的futures类来实现异步返回结果的协调问题。

Future<HttpServer> httpServerFuture = Future.future();
httpServer.listen(httpServerFuture.completer());

Future<NetServer> netServerFuture = Future.future();
netServer.listen(netServerFuture.completer());

CompositeFuture.all(httpServerFuture, netServerFuture).setHandler(ar -> {
if (ar.succeeded()) {
// All server started 全部成功
} else {
// At least one server failed 至少一个失败
}
});

CompositeFuture.all可以将所有的future包含起来,然后判断所有的这些future是否全部成功还是有失败的。如上面的例子。

Future<String> future1 = Future.future();
Future<String> future2 = Future.future();
CompositeFuture.any(future1, future2).setHandler(ar -> {
if (ar.succeeded()) {
// At least one is succeeded 至少有一个是成功的
}
else {
// All failed 全部失败
}

});

CompositeFuture.any 跟all的意思一样,但是判断成功失败的条件不一样。

FileSystem fs = vertx.fileSystem();

Future<Void> fut1 = Future.future();
Future<Void> fut2 = Future.future();

fs.createFile("/foo", fut1.completer());
fut1.compose(v -> {
fs.writeFile("/foo", Buffer.buffer(), fut2.completer());
}, fut2);
fut2.compose(v -> {
fs.move("/foo", "/bar", startFuture.completer());
}, startFuture);

以上代码表明,compose方法可以链式的调用Future。

参考文档地址:http://vertx.io/docs/vertx-core/java/