Vert.x 3 core:
Vert.x core主要提供了一下功能:
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
Vertx vertx = Vertx.vertx();
你可以直接使用以上代码获取vertx对象,以便能很便捷的使用。不过我们大多数的app只是单个的vertx对象,再一些特殊情况下可能使用多个,例如:事件总线或者多个服务端或者多个客户端之间。
创建vertx对象还可以使用一些参数来创建:
Vertx vertx = Vertx.vertx( new VertxOptions().setWorkerPoolSize(40) );
VertxOptions对象就是包含这些设置参数的对象。
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读取数据,向磁盘写入数据,向一个容器发送数据并等待返回,等等。
大多数的情况下,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。
(黄金法则:不要阻塞event-loop线程)
在讨论之前,我们不应该直接的在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(见后面章节)
通过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/