Vert.x学习
还在沉迷于node.js、play framework、akka?你out了!该试试vert.x了。vert.x是一个用于构建运行在jvm上的响应式应用的工具箱和分布式应用开发平台。目前最新版本是3.X,相比2.0版本已经成熟很多了。
vert.x的特性
1.多语言:除了java语言外,还支持javascript、ruby、python、scala、groovy、clojure、php
等动态语言,这个很大程度归功于JVM对动态语言的支持。vert.x中的x即表示多语言的意思。可以用这些语言来开发基于vert.x的应用,也可在一个应用中混合多种语言,例如在一个jvm中混合使用java和javascript。
图1
图1展示的是在一个JVM进程中有四种语言(ruby、groovy、javascript、java)编写的组件(verticle)。
2.非阻塞/事件驱动:非阻塞、异步、多路复用是高性能的关键,特别是在IO密集型的场景中,这些内容在C10k/C1XK问题中较深入的讨论。vert.x使用Multi-Reactor Pattern,使用多线程事件循环,这个要好于node.js的单线程处理模型。
3.灵活通用:用途广泛,既可用于一般的简单网络类应用,也可用于复杂的web应用、微服务、大容量的事件系统和消息系统等。它底层的网络库采用netty,支持http客户&服服务器、webscoket、tcp/udp、dns客户端应用的开发。
4.轻量:Vert.x核心包(core)只有650kB,基于它开发的web应用和服务不需要application server,如tomcat、jetty。伴随着Vert.x的成熟,也预兆着java application server将逐渐死亡或衰落。
5.负载均衡和高可用集群:这个是开箱即用的,只要配置下就行。
和node.js的比较
和node.js相比,vert.x在多语言、性能、通用性等方面都具有较大优势,在多项基准测试中成绩名列前茅,几乎都在前三,比node.js要快。node.js的功能是vert.x的子集。
vert.x的架构
图2
图3
图4
vert.x实例
vert.x实例是vert.x api的入口点,我们调用vert.x中的核心服务时,均要先获取vert.x实例,通过该实例来调用相应的服务,例如部署verticle、创建http server。
一个JVM中通常只有一个vert.x实例,也可有多个实例。每个vert.x实例有自己的事件循环(一个事件循环对应一个事件循环线程),其事件循环数量缺省是cpu核数的2倍(文档中提到缺省数量等于cpu核数,但经过测试发现vert.x 3.1.0版本中是2倍)。
verticle
verticle是vert.x中的组件,可理解成java中的servlet、pojo bean或akka中的actor。一个组件可有多个实例。verticle实例之间的通讯通过Event Bus,发消息到Event Bus。
verticle可分为两种类型:标准verticle和worker verticle。
标准verticle运行在vert.x实例的事件循环线程中,也就是当有事件发生时,在事件循环线程中回调verticle实例中的event handler。
一个vert.x实例可有多个标准verticle实例,每个标准verticle实例中的event handler当事件发生时总是在一个固定的事件循环线程中被回调,因为在固定的单线程中运行,在一定程度上避免了竞争条件和死锁。标准verticle(更确切的说是verticle event handler中的回调方法)不能阻塞事件循环。
worker verticle在background workers线程池中执行,该线程池的大小缺省为40。worker verticle又可分成两种,一种是多线程worker verticle,一个多线程worker verticle实例可在多个worker线程中并发执行,另一种是单线程worker verticle,在同一时间只能有一个线程执行(串行执行),但在不同时间可被不同线程执行。
event bus
event bus可理解为一个分布式的消息队列系统,支持点对点(队列)、发布-订阅(topic)、请求-响应模式。verticle实例之间的事件均通过event bus进行传递,这些verticle实例可分布在不同的JVM或不同机器上,也可在用户的web浏览器上。如图4所示。
对可能阻塞事件循环的操作或任务,可调用context的executeBlocking方法,将操作放到worker线程池中执行或通过event bus发消息触发worker verticle执行。
安装vert.x工具箱
vert.x目前的最新版本是3.1.0.可在https://bintray.com/vertx/downloads/distribution/3.1.0/view下载vert.x-3.1.0-full.zip,解压后将bin路径加到path中。运行vertx version命令,输出3.1.0即表示正确安装。
vertx命令可用来启动、停止vertx开发的应用,但在开发阶段vertx工具箱的安装不是必须的,结合maven可以自动下载vertx的jar包,使用java命令即可运行vertx开发的应用。
如何学习vert.x
vert.x很容易上手,目前学习方式主要是阅读官方网站上的文档和例子,网上也有书籍,不过是针对2.0版本的。
研读文档
通过研读官方网站上的文档(http://vertx.io/docs/)了解vert.x的架构、基本概念和相关api介绍。
Core是vert.x的核心模块,可先看Core模块的文档,其他是外围模块或扩展模块,如web、Data access(mysql/mongodb/redis/...),如要编写web服务,需要查阅web模块的文档。
github上的vertx-examples
官网文档中有相关Examples代码的github网址链接:https://github.com/vert-x3/vertx-examples 下载页面中的zip包后解压,在以maven项目导入到eclipse中即可。
blog
http://tutorials.jenkov.com/vert.x/index.html 有很不错的入门系列
几个例子
1)javascript版本的http server
这个是vertx-examples中的maven-verticle-javascript项目,只有一个js文件MyJavaScriptVerticle.js,内容如下
vertx.createHttpServer().requestHandler(function (req) {
req.response().putHeader("content-type", "text/html").end("<html><body><h1>Hello from vert.x!</h1></body></html>");
}).listen(8080);
上面的代码创建一个在8080端口监听的http webserver。其中vertx就是vert.x实例,这个文件可以认为对应一个javascript版的verticle。createHttpServer创建http webserver,function (req)是请求的event handler,该handeler中设置http响应的content-type头,使用end设置http body并结束请求处理,发送响应数据。
在该项目的README.adoc有如何运行的方法,该文件内容如下:
= Vert.x 3.0 Simple Maven Verticle for JavaScript project
This project is very similar to the maven-verticle project but instead of using a Java verticle is uses a JavaScript
verticle.
You can run it directly in your IDE by creating a run configuration that uses the main class `io.vertx.core.Launcher`
and passes in the arguments `run src/main/js/MyJavaScriptVerticle`.
The pom.xml uses the Maven shade plugin to assemble the application and all it's dependencies into a single "fat" jar.
To build a "fat jar"
mvn package
To run the fat jar:
java -jar target/maven-verticle-javascript-3.1.0-fat.jar
(You can take that jar and run it anywhere there is a Java 8+ JDK. It contains all the dependencies it needs so you
don't need to install Vert.x on the target machine).
Now point your browser at http://localhost:8080
还有一种方式是用vertx run命令来运行,这个类似于node.js,如下
D:\vertx-examples-master\maven-verticles\maven-verticle-js\src\main\js> vertx run MyJavaScriptVerticle.js
运行后输出:
Succeeded in deploying verticle
或D:\vertx-examples-master\maven-verticles\maven-verticle-js> vertx run src/main/js/MyJavaScriptVerticle.js
打开浏览器输入http://127.0.0.1:8080 或curl http://127.0.0.1:8080 即可看到结果Hello from vert.x!
2)java版本http server,maven-simplest项目
这个项目只有一个java源文件HelloWorldEmbedded.java,
public class HelloWorldEmbedded {
public static void main(String[] args) {
// Create an HTTP server which simply returns "Hello World!" to each request.
Vertx.vertx().createHttpServer().requestHandler(req -> req.response().end("Hello World!")).listen(8080);
}
}
上面的代码中,Vertx.vertx() 创建并返回一个vert.x实例。
这种是嵌入的方式,将vertx嵌入(Embedded)到我们的主体代码中进行使用,需要编写一个main方法。
还有一种方式是以vertx为主,使用vertx core模块中的io.vertx.core.Launcher作为main class,该类中有main方法。
3)spring-example项目
这个项目是嵌入式的方式,结合spring框架来使用,main方法在SpringExampleRunner.java类中,该文件内容如下
public class SpringExampleRunner {
public static void main( String[] args ) {
ApplicationContext context = new AnnotationConfigApplicationContext(ExampleSpringConfiguration.class);
final Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new SpringDemoVerticle(context));
vertx.deployVerticle(new ServerVerticle());
}
}
vertx.deployVerticle用来部署verticle实例,如果要部署多个SpringDemoVerticle实例,可重复调用vertx.deployVerticle(new SpringDemoVerticle(context));
也可采用如下代码来部署多个SpringDemoVerticle实例(3个),并且设置为woker verticle
DeploymentOptions options = new DeploymentOptions();
//3个实例
options.setInstances(3);
//worker verticle,缺省是标准verticle
options.setWorker(true);
vertx.deployVerticle(new SpringDemoVerticle(context),options);
deployVerticle方法还有其他几个版本,例如deployVerticle(String name),对java verticle,传的是verticle的全限定类名。
还有个springboot-example项目演示的是如何结合spring boot来使用vertx。
4) maven-verticle项目
我对该项目进行了修改,增加了一个cosumer.js文件,使用event bus的点对点消息通讯机制,也用于演示javascript和java的混合开发,这个多语言开发是vertx的特性之一,在最后面有源码下载。
HelloWorldVerticle.java
public class HelloWorldVerticle extends AbstractVerticle {
@Override
public void start() {
// Create an HTTP server which simply returns "Hello World!" to each request.
// If a configuration is set it get the specified name
//发布js文件中的verticle,该verticle用来消费event bus中的消息,消息地址为notify
vertx.deployVerticle("test/cosumer.js");
String name = config().getString("name", "World");
vertx.createHttpServer().requestHandler(
req -> {
//end发送http应答
req.response().end("Hello " + name + "!");
//发送http响应后,发送一个消息到evnet bus的notify消息地址,welcome!是消息内容
vertx.eventBus().send("notify","welcome!");
}
).listen(8080);
}
}
我们编写的HelloWorldVerticle继承AbstractVerticle,该类中有个Vertx vertx成员(vert.x实例)可拿来直接使用。该verticle由前面提到的io.vertx.core.Launcher来负责部署,
start方法为启动方法,每个verticle实例在部署时均会调用一次start方法,该方法在它所属的事件循环线程中被调用(假设是标准verticle)。在start方法中可以调用vertx.deployVerticle
方法来部署子verticle实例,如上面的vertx.deployVerticle("test/cosumer.js");
cosumer.js文件位于src/main/js/test目录,内容如下:
//返回event bus
var eb = vertx.eventBus();
//消息地址
var address = 'notify'
//消息消费者handler(回调方法),这里只是将消息输出到控制台上
var handler = function(message) {
console.log("msg:" + message.body());
}
//注册消息消费者
eb.consumer(address, handler);
console.log("start");
编译运行
命令行运行mvn package或eclispe使用maven进行打包生成maven-verticle-3.1.0-fat.jar和maven-verticle-3.1.0.jar。maven-verticle-3.1.0-fat.jar中包含有运行需要的所有文件和资源。
使用java -jar target/maven-verticle-3.1.0-fat.jar 运行
或vertx run io.vertx.example.HelloWorldVerticle -cp target/maven-verticle-3.1.0.jar
或vertx run io.vertx.example.HelloWorldVerticle -cp target/maven-verticle-3.1.0-fat.jar
也可使用现场编译java文件来运行
vertx run HelloWorldVerticle.java -cp ../../../../js
-cp是为了指定test/cosumer.js的路径
在vertx 后面还可加-instances 选项来指定verticle的实例数,例如-instances 2
启动后,浏览器中输入http://127.0.0.1:8080 返回Hello World!,同时在控制台上开看到输出msg:welcome!,这个就是cosumer.js中的消息消费者输出的。
在maven-verticle-3.1.0-fat.jar压缩包的META-INF\MANIFEST.MF中存在如下两项:
Main-Verticle: io.vertx.example.HelloWorldVerticle
Main-Class: io.vertx.core.Launcher
这两项内容在pom.xml文件中设置:
<manifestEntries>
<Main-Class>io.vertx.core.Launcher</Main-Class>
<Main-Verticle>${main.verticle}</Main-Verticle>
</manifestEntries>
Main-Verticle表示主Verticle,为io.vertx.example.HelloWorldVerticle。
除了可在代码中设置verticle实例的个数,还可在vertx命令中设置主verticle的实例数,使用-instances选项,例如设置两个verticle实例:
vertx run io.vertx.example.HelloWorldVerticle -cp target/maven-verticle-3.1.0-fat.jar -instances 2
vert.x中的其他组件和模块
vert.x的外围模块还是比较丰富的,下面只简要介绍部分模块和组件。这些都是支持多语言开发的,可选用你熟悉的语言来使用。
1) web模块
上面的例子使用的是玩具代码,如果要开发企业级的web应用或restful api,就需要使用vertx-web模块,它提供了诸多特性,如路由器(用来映射url到handler上进行处理 )等,可理解成提供了spring mvc类似的功能。
2)共享数据组件SharedData
Shared data provides:
Cluster wide maps which can be accessed from any node of the cluster
Cluster wide locks which can be used to give exclusive access to resources across the cluster
Cluster wide counters used to maintain counts consistently across the cluster
Local maps for sharing data safely in the same Vert.x instance
可见shareddata提供了集群(分布式)map、集群(分布式)lock、集群counter计数器、本地map(用于同一Vert.x instance内)。
3)Reactive响应式模块
Vert.x Rx:
Don't like callback-style APIs? Vert.x provides Rx-ified (using RxJava) versions for most of its APIs so you can use those if you prefer.
RxJava is a great choice when you want to perform complex operations on multiple asynchronous streams of data.
Reactive streams:
Vert.x supports reactive streams so your applications can interoperate with other reactive systems such as Akka or Project Reactor.
Vert.x Sync:
Vertx-sync allows you to deploy verticles that run using fibers. Fibers are very lightweight threads that can be blocked without blocking a kernel thread.
This enables you to write your verticle code in a familiar synchronous style.
这个Sync使用fiber(coroutine协程)技术,使异步执行的代码从静态代码层面看起来似乎是同步执行的,这样更符合开发人员的编程习惯,提高编程效率。它可用来解决多层嵌套回调产生的回调地狱问题。
参考网址:
http://vertx.io/docs/vertx-core/java/
上一篇: 读写分离情况下的读自己写一致性
下一篇: 一大波视频分享