事件总线是一种集中式事件处理机制,它允许不同的组件之间进行彼此通信而又不需要相互依赖,从而达到解耦的目的。它是对发布-订阅模式的一种实现,可以看作是一个中心化的媒介,能够以标准化的协议在这些组件之间路由事件,负责将事件从发布者传递给订阅者。事件总线可以管理事件的传递、路由和解析,同时也可以处理事件的顺序、优先级和过滤。
在事件驱动型架构中,事件总线是其中的一部分,它主要用于处理事件发布和订阅的中间件。它通过提供统一的订阅、取消订阅和发布接口,使不同组件或模块之间能够进行松散耦合的通信。
事件总线的设计基于观察者模式的思想,使用发布-订阅的方式支持组件和模块间的通讯,摒弃了观察者模式需要显示回调的缺点。在事件总线上,事件被发送到一个总线上,然后由订阅该事件的订阅者处理。订阅者不仅可以接收和消费事件,它们本身也可以创建事件,并将它们发送到事件总线上。
事件总线还可以维护一个事件源与事件处理的映射字典,提供统一的订阅、取消订阅和发布接口。事件是一个普通的POJO类,只包含数据,不包含对数据的操作。订阅者存在优先级,优先级高的订阅者可以取消事件继续向优先级低的订阅者分发,默认所有订阅者优先级都为0。总线负责订阅者、事件等信息的存储,同时处理事件的流动和分发,通过总线,订阅者和发布者是解耦的,互不知道对方的存在。
Vert.x是一个基于事件驱动的开源框架,用于构建响应式应用。在Vert.x中,事件总线是一个核心概念,用于实现不同组件之间的通信和数据传递。
事件总线是一个消息传递平台,允许Vert.x中的各个组件(Verticle)通过发布和订阅事件来进行通信。它类似于消息队列,但更灵活,支持发布-订阅和点对点两种消息传递模式。
在Vert.x中,每个事件都有一个唯一的地址(address),发布者将消息发送到该地址,订阅者则监听该地址的消息。事件总线独立于应用系统,使用TCP协议进行通信,因此可以在任何能够创建TCP连接的应用中使用。
事件总线具有以下特点:
Vert.x中的事件总线是一个强大而灵活的消息传递平台,为构建响应式应用提供了坚实的基础。通过事件总线,Vert.x能够实现高度解耦的组件通信、分布式能力、集群通信和异步通信等功能,从而满足各种复杂的应用需求。
在Vert.x中,事件总线的实现方式是通过Vert.x的事件模型。具体来说,事件总线是Vert.x的神经系统,负责应用系统消息的传递。每个事件在事件总线上都有一个唯一的地址(address),发布者向该地址发送消息,而订阅者则监听该地址的消息。
每个Verticle(Vert.x的模块)都可以发布和订阅事件,通过事件总线进行通信和数据传递。这种通信方式使得Vert.x中的模块高度解耦,降低了系统的复杂性,并提高了可维护性和可扩展性。
事件总线使用TCP协议进行通信,因此可以在任何能够创建TCP连接的应用中使用。此外,事件总线还支持分布式结构,可以将事件总线延伸到不同的Vert.x实例中,实现复杂的分布式应用。
在Vert.x中,可以通过简单的API来使用事件总线。例如,可以使用vertx.eventBus().send()
方法发送消息,使用vertx.eventBus().registerHandler()
方法注册消息处理器等。
Vert.x的事件总线提供了一种灵活、可靠的消息传递机制,使得Vert.x能够构建高性能、可扩展的应用。
Vert.x的事件总线和我们在开发中常用的消息队列有非常多的相似之处,但是事件总线并不是消息队列,Vert.x的事件总线并不能替代 RabbitMQ 、Kafka等这些消息队列,事件总线和消息队列是两种不同的消息传递模式,它们在功能和实现上有一些区别。
事件总线通常用于系统或进程内部,作为组件之间通信的机制。它采用发布-订阅模式,允许发布者发布事件,而多个订阅者可以监听这些事件。事件总线具有广播性质,一个事件一旦发布,所有订阅了该事件的订阅者都会收到消息。事件总线通常用于解耦组件间的依赖关系,使组件可以独立地开发和部署。主要用于应用程序内的各Verticle间的通信,而不是应用程序间的通信,Vert.x的事件总线不支持以下功能:
事件总线仅用于承载易失性事件,这些事件由Verticle异步的进行处理
消息队列是一种更古老的消息传递模式,其特点是消息的传递是异步的。生产者将消息放入队列,而消费者从队列中获取并处理这些消息。消息队列保证了消息的有序性和可靠性,同时提供了消息的持久化和事务处理等功能。在分布式系统中,消息队列可以作为各个组件间通信的桥梁,用于集成不同的服务或系统。
事件总线和消息队列的区别主要在于其使用场景和特点。事件总线主要用于系统或进程内部的组件间通信,强调解耦和灵活性;而消息队列则主要用于分布式系统中的跨服务或跨系统间的通信,更注重消息的可靠性和有序性。在实际应用中,可以根据需要选择适合的消息传递模式。
在“点对点”模式下,消息从生产者发送到各个目标地址,如图的a.b.c目标地址可以是任意格式的字符串, Vert.x 社区的默认约定是使用点号分隔的字符串。在“点对点”通信中,如果存在多个消费者,则只有一个会取得消息和处理消息。图中的消息 M1、M2、M3 展示了这一场景。
消息通常以循环调度方式在消费者之间分发,因此消费者可以均等地分担消息处理工作。所以在图中,第一个消费者处理 M1,而第二个消费者处理 M2、M3。注意,你可能会想,给负担过重的消费者少发一些消息,但是“点对点”模式并没有提供这样的平衡机制。
在 Vert.x 中,“请求-应答”通信是“点对点”通信的变体。在“点对点”消息通信中,发送一条消息时可以同时注册一个应答程序。执行过程中,事件总线将生成一个临时目标地址,专门用于该消息创建者与消费者(最终接收和处理该消息)之间的通信。
这种消息通信模式适用于模拟 RPC(远程过程调用),只不过响应是以异步方式发送的,因此请求方不需要一直等待响应返回,
这种模式如图所示。当一条消息需要回复时,事件总线会生成一个回复地址,并在消息到达消费者之前将该地址附加到消息中。需要的话,也可通过事件总线提供的 API来查看该回复地址,但实际场景中很少需要知道这个地址,我们只需要在消息对象上调用 reply 方法。当然,在使用此模式时,消费者这一端需要编程来提供答复。
在“发布-订阅”通信模式中,生产者和消费者之间具备更高程度的解耦。当消息目标地址时,所有订阅者都会收到它,如图所示。消息 M1、M2 和 M3 由不同的生产送,并且所有订阅者都会接收到消息,这与“点对点”消息通信不同。另外也不能为事件总线上的“发布-订阅”通信指定答复程序。
当你不确定有多少个 Verticle 及其处理程序对某个事件感兴趣时,可使用“发布-订阅式。如果你需要消息的消费者给消息的发送方发送回复,则请使用“请求-应答”模式。究竟选择“点对点”模式,还是“发布-订阅”模式,这是一个功能需求问题,主要取决件是需要交给所有消费者处理,还是只需要交给某一个消费者处理。
在Vert.x中,事件总线可以应用于许多场景,主要包括构建响应式、高并发、实时数据处理的系统。具体来说,事件总线可以用于以下场景:
总之,事件总线在Vert.x中提供了一种灵活、可靠的消息传递机制,使得Vert.x能够构建高性能、可扩展的应用。
下面是一个使用Vert.x的事件总线示例,其中有两个Verticle:SenderVerticle和ReceiverVerticle。SenderVerticle发布事件,ReceiverVerticle订阅事件并处理它。
public class SenderVerticle extends Verticle {
@Override
public void start() {
vertx.eventBus().send("my.address", "Hello, Vert.x!");
}
}
public class ReceiverVerticle extends Verticle {
@Override
public void start() {
vertx.eventBus().consumer("my.address", message -> {
String body = message.body().toString();
System.out.println("Received message: " + body);
});
}
}
public class Main {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new SenderVerticle());
vertx.deployVerticle(new ReceiverVerticle());
}
}
在这个示例中,SenderVerticle向地址"my.address"发送一条消息"Hello, Vert.x!",而ReceiverVerticle订阅该地址,并打印接收到的消息。通过事件总线,SenderVerticle和ReceiverVerticle可以解耦地进行通信。
在Vert.x中,事件总线的消息类型可以是任何Object,包括Boolean、String等基本类型,也可以是自定义类型的消息。这些消息可以用来传递各种数据,例如状态更新、事件处理结果、消息确认等。
事件总线的消息类型是动态的,可以根据实际需要定义不同的消息类型。例如,在物联网系统中,事件总线的消息类型可以是传感器数据、控制指令等;在网络应用程序中,事件总线的消息类型可以是用户输入、服务器响应等。
在Vert.x中,事件总线的消息类型是通过消息通道来区分的。每个消息通道都有一个唯一的名称,用于标识不同类型的消息。订阅者可以根据需要订阅不同的消息通道,从而接收不同类型的消息。发布者则通过指定消息通道的名称来发布不同类型的消息。
事件总线的消息类型是灵活的,可以根据实际需要定义不同的消息类型,从而实现各种不同的应用场景。
下面是与Vert.x相关的一些其它博文链接,希望可以帮助大家进一步的了解Vert.x的相关知识