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

时间:2022-10-04 18:06:26

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

Verticles

verticles是一个很重要的概念。你可以将verticles当做是Actor Model(一种编程模型)中的actor。它是一段代码的集合—可以部署和被Vert.x运行。并且verticles能够被Vert.x支持的所有语言编写,并不仅限于java。一个应用可以包含不同语言编写的verticles。所有的verticles之间通过event bus进行交换数据。

Writing Verticles

所有编写的Verticle类都必须继承Verticle接口。为了方便,一般情况下我们可以继承AbstractVerticle。如下代码:

public class MyVerticle extends AbstractVerticle {

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

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

}

当verticle部署运行时,会调用start方法;当start方法运行完后,就认为verticle已经启动。当verticle卸载时,会调用stop方法;当stop方法运行完成后,就认为verticle已经卸载。

Asynchronous Verticle start and stop

如果你需要在verticle的start方法中执行比较耗费时间的操作时,你不能为了等待其部署,而去阻塞。这样就违背了黄金原则。那么我们应该怎么做呢?

public class MyVerticle extends AbstractVerticle {

public void start(Future<Void> startFuture) {
// Now deploy some other verticle:

vertx.deployVerticle("com.foo.OtherVerticle", res -> {
if (res.succeeded()) {
startFuture.complete();
} else {
startFuture.fail();
}
});
}
}

如上代码所示,我们可以继承异步的start方法(多一个startFuture参数)。例子中展示的是我们在一个verticle的start方法中启动另一个verticle。
相对应的stop方法也有异步的实现,如下代码:

public class MyVerticle extends AbstractVerticle {

public void start() {
// Do something
}

public void stop(Future<Void> stopFuture) {
obj.doSomethingThatTakesTime(res -> {
if (res.succeeded()) {
stopFuture.complete();
} else {
stopFuture.fail();
}
});
}
}

note:我们不需要在stop方法中去卸载一个子verticle,因为vert.x会在我们卸载父verticle时一并卸载子verticle。

Verticle Types

  • Standard Verticles
    基本的类型。他们总是使用event loop线程执行。
  • Worker Verticles
    他们通过work pool里面的线程来运行。一个实例不能被多于一个线程使用。
  • Multi-threaded worker verticles
    他们通过work pool里面的线程来运行。他们的一个实例可以被多个线程并行的执行。

Standard verticles

当standard verticles被event-loop线程创建和执行start方法时,vertx会分配到一个event-loop线程。当我们调用verticle的其他方法时,比如handler,vertx保证我们的handler在被调用时在同一个event-loop中执行。这也就能确保我们所有的verticle代码都会在同一个event-loop中被执行。

Worker verticles

Worker verticles和Standard verticles是比较像的,只是他不是在event-loop线程中执行,而是从work pool中取出一个线程来执行。Worker verticles被设计用来执行阻塞的代码,因此不能阻塞任何的event-loop线程。
如果你不希望使用worker verticle来运行阻塞的代码,也可以直接在event-loop线程中运行inline blocking code(见之前的文章)。
如果你希望部署一个verticle作为一个work verticle,可以如下设置:

DeploymentOptions options = new DeploymentOptions().setWorker(true);
vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options);

worker verticle不能被并行的执行(不能被多个线程同时运行),但是可以被不同的线程在不同的时间运行。

Multi-threaded worker verticles

Multi-threaded worker verticles和worker verticle很像,但是他可以被并行的执行(能被多个线程同时运行)。

Deploying verticles programmatically

你可以使用deployVerticle方法来定义部署一个verticle,通过一个verticle的类名,或者verticle的实例。

Verticle myVerticle = new MyVerticle();
vertx.deployVerticle(myVerticle);
vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle");

Rules for mapping a verticle name to a verticle factory

当使用verticle类名来部署一个verticle时,vertx会去寻找初始化verticle的工厂类。
我们可以使用前缀来指定工厂:

js:foo.js // Use the JavaScript verticle factory
groovy:com.mycompany.SomeGroovyCompiledVerticle // Use the Groovy verticle factory
service:com.mycompany:myorderservice // Uses the service verticle factory

如果没有前缀,vertx将通过后缀来选择工厂:

foo.js // Will also use the JavaScript verticle factory
SomeScript.groovy // Will use the Groovy verticle factory

如果没有前缀和后缀,那么vertx将会当成是java的全类路径来解析。

How are Verticle Factories located?

Most Verticle factories are loaded from the classpath and registered at Vert.x startup.
You can also programmatically register and unregister verticle factories using registerVerticleFactory and unregisterVerticleFactory if you wish.
这一段就不翻译了。

Waiting for deployment to complete

verticle的部署是异步的。如果你希望在verticle部署完成时得到通知,你可以注册一个handler来实现:

vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", res -> {
if (res.succeeded()) {
System.out.println("Deployment id is: " + res.result());
} else {
System.out.println("Deployment failed!");
}
});

The completion handler will be passed a result containing the deployment ID string, if deployment succeeded.
This deployment ID can be used later if you want to undeploy the deployment.

部署成功后会返回deployID,deployID在卸载的时候会用到。

Undeploying verticle deployments

通过deployID来卸载。卸载也是异步的。

vertx.undeploy(deploymentID, res -> {
if (res.succeeded()) {
System.out.println("Undeployed ok");
} else {
System.out.println("Undeploy failed!");
}
});

Specifying number of verticle instances

在部署verticle时,我们可以通过指定数量来决定我们部署多少个相同的verticle。

DeploymentOptions options = new DeploymentOptions().setInstances(16);
vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options);

Passing configuration to a verticle

通过json来配置:

JsonObject config = new JsonObject().put("name", "tim").put("directory", "/blah");
DeploymentOptions options = new DeploymentOptions().setConfig(config);
vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options);

Accessing environment variables in a Verticle

Environment variables and system properties are accessible using the Java API:

System.getProperty("prop");
System.getenv("HOME");

Verticle Isolation Groups(隔离组)

有的时候我们希望将不同的或者相同的verticle进行隔离部署,例如相同的verticle,不同的版本。

DeploymentOptions options = new DeploymentOptions().setIsolationGroup("mygroup");
options.setIsolatedClasses(Arrays.asList("com.mycompany.myverticle.*",
"com.mycompany.somepkg.SomeClass", "org.somelibrary.*"));//此处部署的verticle会进行隔离加载
vertx.deployVerticle("com.mycompany.myverticle.VerticleClass", options);//此处的VerticleClass会使用当前的classload进行加载。

note:使用此特性,会带来维护和debug等的难度。

High Availability

verticles能够进行高可用的部署。需要使用如下命令来启用此特性:

vertx run my-verticle.js -ha

启用高可用不需要-cluster参数。当verticle突然中断时,其他vertx会重新部署一个此verticle。

Running Verticles from the command line

To do this you need to download and install a Vert.x distribution, and add the bin directory of the installation to your PATH environment variable. Also make sure you have a Java 8 JDK on your PATH.

vertx run SomeJavaSourceFile.java

Causing Vert.x to exit

vertx实例的主线程将以守护线程的方法运行,因此将会阻止jvm退出。如果需要通过变成退出的话,可以调用close方法。

The Context object

可以使用如下代码来获取上下文对象:

Context context = vertx.getOrCreateContext();

获取到上下文对象后,我们就可以在其上运行代码:

vertx.getOrCreateContext().runOnContext( (v) -> {
System.out.println("This will be executed asynchronously in the same context");
})
;

当有多个handler运行在同一个context上时,我们就可以通过context来共享数据。

final Context context = vertx.getOrCreateContext();
context.put("data", "hello");
context.runOnContext((v) -> {
String hello = context.get("data");
});

context对象也让你访问verticle对象的配置,通过config方法。

Executing periodic and delayed actions(执行周期和延迟动作)

在verticle中,不能采用暂停线程的方式来执行周期和延迟的动作。那样会阻塞event-loop。
Instead you use Vert.x timers. Timers can be one-shot or periodic.

one-shot

long timerID = vertx.setTimer(1000, id -> {
System.out.println("And one second later this is printed");
});

System.out.println("First this is printed");

Periodic Timers

long timerID = vertx.setPeriodic(1000, id -> {
System.out.println("And every second this is printed");
});

System.out.println("First this is printed");

Cancelling timers

vertx.cancelTimer(timerID);

Automatic clean-up in verticles

If you’re creating timers from inside verticles, those timers will be automatically closed when the verticle is undeployed.