注意:使用的是vert.x3.0 仅支持到java8其中有一些lambda表达式,如不明白请自补java8新特性。
The Event Bus
event bus 是vert.x的神经系统。
每一个vert.x的实例都有一个单一的event bus 实例。它是使用vertx.eventBus()方法获得的。
event bus 允许程序中的不同语言编写的模块进行通信,不论他们是相同的vert.x实例,还是不同的vert.x实例。
它甚至可以桥接浏览器中运行的Javascript通信。
event bus可以在分布式系统中的多个服务器节点之间进行点对点通信和多个浏览器。
event bus支持发布/订阅模式,点对点模式,和请求/响应模式。
event bus的API是非常容易的,它主要包括注册消息处理事件,取消处理事件,发送和发布消息。
首先理论
寻址
event bus上的消息被发送到一个地址。
vert.x不包含任何花哨的寻址方案。在vert.x中,一个地址就是一个简单的String字符串,任何字符串都是有效的。不过最好的方法是使用某种有计划或者有规则的方案,比如使用一个私有的空间名称。
一些有参考价值的例子:europe.news.feed1, acme.games.pacman, sausages, and X。
事件-消息的处理程序
收到消息的处理程序,你在一个地址上注册一个处理程序,来消息后将触发这个处理程序。
同一个消息处理程序可以注册到不同的地址上,同样同一个地址也能注册多个处理程序。
发布/订阅模式
event bus 支持发布消息
消息被发布到一个地址。发布意味着将消息交给所有订阅并注册处理程序的地址来处理。
这跟大家熟悉的发布/订阅模式没有什么不同。
点对点和请求/响应模式
event bus 支持点对点消息传递。
消息被发送到一个地址。vert.x将发送它到一个注册消息处理程序的地址。
如果有多个处理程序注册地址,vert.x将选择一个来处理(采用非严格循环算法)。强烈不推荐。
当接收到消息的程序处理完成后,可以决定是否回复,发送程序接到回复后也可以进行响应回复,如果他们这样做应答处理程序将被调用。
当接收方到返回发送方,这样可以无限重复,这又是一种常见的消息传递模式:请求/响应模式
最优传输
vert.x能够做到最优传输,不会有意识的丢失消息。这是非常重要的。
然而,event bus的部分或全部失败还是有可能造成消息丢失的。
如果你的应用程序非常在乎消息的完整性和时序性,那么你的代码处理应该是幂等的,以便在消息处理程序复苏后重新发送消息。
消息类型
开箱允许vert.x使用任何的原始/简单类型,字符串或者缓冲区发送消息。
然而这里有一个不成文的规定或者说建议。那就是最好使用JSON格式的子串来进行消息的传递。
JSON字串在所有的编程语言中都是非常容易创建,读取和解析的。在vert.x下它已经变成一种通用语言了。
如果你没必要使用JSON或者说你不想。
event bus 非常灵活。它还支持发送任意对象。还可以定义您想要发送的对象的编解码器。
EVENT BUS 的API
让我们跳进event bus的API。
获得event bus 的对象
你可以通过如下代码获得event bus的单一对象:
EventBus eb = vertx.eventBus();
注册处理事件
使用下面这个简单方法注册一个消费处理程序:
EventBus eb = vertx.eventBus();
eb.consumer("news.uk.sport", message -> {
System.out.println("I have received a message: " + message.body());
});
当一个消息到达你的处理事件是。你的事件将被激活,并处理这个消息。
consumer()方法返回一个MessageConsumer的对象实例。这个对象随后用于注销处理程序,或者用处理程序作为流。
然而您也可以使用consumer()返回MessageConsumer没有处理程序,然后单独设置处理程序。例如:
EventBus eb = vertx.eventBus();
MessageConsumer
System.out.println("I have received a message: " + message.body());
});
当在集群事件总线上注册一个处理程序时,它可以花一些时间登记到集群的所有节点上。
如果你希望在注册完成时得到通知的话,你可以在MessageConsumer上注册一个注册完成的处理程序:
consumer.completionHandler(res -> {
if (res.succeeded()) {
System.out.println("The handler registration has reached all nodes");
} else {
System.out.println("Registration failed!");
}
});
注销处理事件
去除处理事件,叫做注销。
如果你是集群事件总线, 如果你想当这个过程完成时通知注销,你可以使用下面的方法:
consumer.unregister(res -> {
if (res.succeeded()) {
System.out.println("The handler un-registration has reached all nodes");
} else {
System.out.println("Un-registration failed!");
}
});
发布消息
发布消息非常简单,只需要把它发布到指定地址即可:
eventBus.publish("news.uk.sport", "Yay! Someone kicked a ball");
这一消息将被交付所有订阅news.uk.sport地址处理。
发送消息
发送消息将导致只有一个注册地址的处理程序接收到消息(多个注册地址也只有一个能收到)。这就是点对点模式,选择处理程序的方法采用非严格循环方式。
你可用用send()方法发送一条消息。
eventBus.send("news.uk.sport", "Yay! Someone kicked a ball");
未解决的指令包括在
你的消息处理程序收到的是一个Message。
消息的body对应着是应该发送还是应该发布。
消息的headers是可用的。
回复消息
有时你发送消息后希望得到接收到消息的人的回复。这就需要你使用请求-响应模式。
要做到这一点,在消息发送的时候,你可以指定一个回复事件。
当你接收到消息的时候,你可以通过调用reply()方法来应答。
当这一切发生的时候它会导致一个答复发送回发送方,发送方收到应答消息再做处理。
接收方:
MessageConsumer
consumer.handler(message -> {
System.out.println("I have received a message: " + message.body());
message.reply("how interesting!");
});
发送方:
eventBus.send("news.uk.sport", "Yay! Someone kicked a ball across a patch of grass", ar -> {
if (ar.succeeded()) {
System.out.println("Received reply: " + ar.result().body());
}
});
对应答也可以做应答。这样你就可以在两个不同的程序中创建一个包含多个回合的对话。
发送超时
当你发送消息时和指定应答事件时你可以通过DeliveryOptions指定超时时间。
如果应答事件不少于超时时间,这个应答事件将失败。
默认的超时时间是30S。
发送失败
消息发送失败的其他原因,包括:
没有可用的事件去发送消息
接收者已经明确使用失败:失败的消息
在所有情况下,应答事件将回复特定的失败。
未解决的指令包含在
event bus 不仅仅存在于一个单一的Vert.x实例中,在一个集群中不同的Vert.x实例也可以形成一个单一的,分布的事件总线。
集群编程
如果你创建一个Vert.x实例用于集群编程,你需要的得到一个关于集群事件总线配置
VertxOptions options = new VertxOptions();
Vertx.clusteredVertx(options, res -> {
if (res.succeeded()) {
Vertx vertx = res.result();
EventBus eventBus = vertx.eventBus();
System.out.println("We now have a clustered event bus: " + eventBus);
} else {
System.out.println("Failed: " + res.cause());
}});
你应该确保在你的类路径中实现了一个ClusterManager,例如默认的:HazelcastClusterManager。
使用命令集群
你可以使用命令行运行集群:vertx run my-verticle.js -cluster
Automatic clean-up in verticles
If you’re registering event bus handlers from inside verticles, those handlers will be automatically unregisteredwhen the verticle is undeployed.