1. 关于Vert.x
1.1 Vertx是什么
在学习Vert.x前一定要看看官网给他的定位
Eclipse Vert.x is a tool-kit for building reactive applications on the JVM.
所以,我们必须首先搞清楚,Vertx不是类似Spring的那一套大而全的框架或者管理对象的容器、工厂
尽管我们不能期待它承担一个完整的项目脚手架的角色,但是麻雀虽小,五脏俱全,作为一个工具集,它包含web服务器应用(其中又包含对http协议、http2、序列化及反序列化、验证、鉴权等的支持)、数据库客户端、服务通信组件等模块,我们可以根据需要自行组合他们
其中的Vertx core是底层组件,它基于Netty构建而成,其中的核心概念有:
- Vertx实例:Vertx的控制中心,承担对Verticle、event loop等组件的配置、启动等任务
- Event Loop:Vertx应用运行的基本机制,本质上说就是利用固定数量的线程处理所有业务逻辑。由于线程数量可控,编码时无需考虑线程安全,线程资源分配的等问题。每个Vertx实例默认维护的线程数量为2*CPU核数
- Worker Pool:执行阻塞任务所使用的线程池,默认线程数量为20
- Verticle:Vertx应用中的基本部署单位,一般一个Vertx应用包含一个或多个Verticle,不同verticle之间使用event bus进行通信
- Event Bus:不同verticle间的通信工具
1.2. Vertx的特点
-
异步:
维基百科对event loop的定义
the event loop is a programming construct or design pattern that waits for and dispatches events or messages in a program(事件循环是一种架构或设计模式,它等待并分发程序中的事件、消息)
Vertx使用event loop机制处理业务逻辑,这种架构模式提高了系统资源利用率,可以确保处理主业务的线程不会被浪费在等待I/O的结果上,但要做到这些,我们必须更改编码风格,将对I/O结果的处理逻辑用回调的形式一并传递给event loop,Vertx将在action1完成时主动调用我们注册的回调函数
我们的代码将由之前的
result1 = action1()
action2(result1)
变为
action1(
result1 ->
action2(result1)
)
这种代码结构在Vertx项目里随处可见。显然,一旦逻辑变得复杂,多重函数的嵌套将导致回调地狱,Vertx为提供了Promise类解决这种问题,通过传递Promise对象,我们可以以同步的方式处理异步的逻辑。
private Future<Void> action() {
Promise<void> promise = Promise.promise();
// (...)
return promise.future();
}
Vertx4.0承诺所有的异步API都将具有Promise返回值。另外,也可以使用Rxjava以流的方式处理数据
-
模块化及通信的解耦
Vertx使用vertical划分模块,各模块间只能通过event bus通信,而不是通过聚合等方式相互调用,这样我们就不需担心模块间耦合。
event bus使用起来相当简单,它使用Json作为的消息格式,我们仅需在消费端定义监听地址(仅仅是一个字符串),在生产端指定消息发送地址即可,并且它有3种通信模式:
- 请求-响应:向目标地址发送消息并由回调方法处理一个期待响应结果
- 异步推送:直接发送一条信息,不期待响应
- 广播:当多个verticle订阅了相同的地址,以上两种模式发送的消息只能被至多一个消费者收到,而广播模式可以向多个消费者发送消息
当event bus检测到收发方均为本地模块时,他的底层仅仅会对数据做序列化和反序列化的操作,不会增加产生额外消耗。它甚至可以结合官方推出的其他组件(如TCP桥接、集群管理器等)很方便地实现跨进程、跨设备的通信,这使得一个Vertx可以及其方便进行横向拓展
每个vertical默认只使用event loop中的一个线程进行运算,所以模块内部的逻辑是高内聚的,可以随意使用全局变量而无需担心线程安全问题
“多线程”的event loop是Vertx的杀手锏,当一个Vertx实例中的某个vertical负荷过大时,我们可以在Vertx实例启动时直接指定此vertical的部署数量,充分利用CPU资源
2.响应式编程
Don't call us,we'll call you.
响应式的编程范式其实就是设计模式中“观察者模式”的一种实践
我们在设计代码结构(或设计项目架构)时,并不直接地针对某个具体业务给出方案,而是分析业务涉及到的各个角色,并对思考他们自身在项目中的地位以及他们之间的联系,最后构建出各个模块
重点考虑模块是如何与其他模块达到松耦合的:
- 简单使用“观察者模式”:那么在核心逻辑执行前观察者将自身的引用提供给目标对象抽象(被观察的主体),目标对象维护一个观察者列表,待自身特定事件发生时,一次性通知所有的观察者
- Vertx中的vertical仅仅使用evnet bus组件与其他模块通信,并且对任何阻塞操作仅允许通过回调的方式执行后续逻辑
构建一套响应式系统使得系统间各模块协作更为自然,代码健壮性更高
如果不使用第三方框架,单纯自行设计这一套系统的成本是巨大的,仅考虑线程间的同步问题就够喝一壶的了,更不用说如何去满足业务需求
3.工具的使用
但是理想中完美的东西未必能在现实中发我们所预期作用
作为一个贯彻响应式编程思维的工具集,Vertx提供了一整套完善的响应式系统,它对几乎所有一般项目中的业务需求提供了解决方案,但它终究不是一个具有工程属性的重量级框架,例如数据库相关组件仅仅是在原生驱动的基础上提供了一层极薄封装
需要做“规范化”的工程时,使用这样的工具集我们不免陷入“再造轮子”的困境,所以,在项目开始初期时,需要结合多方面因素考虑,选择适合项目的工具,以达到工具的“为我所用”的目的