1、多个客户端或服务器端。Vert.x启动时,会将Worker Vertical的事件处理函数加载到Event Bus,当一个HTTP请求发送到Vert.x构建的应用时,Event Loop首先接收到请求,并对请求做分析、包装,然后将事件交给Event Bus来处理,Event Bus为此次请求事件添加一个事件ID,然后根据注册的Worker Vertical事件寻找已经注册的监听函数,若未找到则会抛弃该事件,若找到则会对处理类进行实例化,并同时使用事件ID在Event Bus中注册一个返回结果处理事件,该事件为Event Vertical类型。下一步由Worker Vertical实例执行事件处
2、理函数,事件处理函数中通常包含业务处理、数据库操作等。Worker Vertical实例处理结束后,将返回结果和事件信息返回给Event Bus,Event Bus找到在其中注册的Event Vertical实例,然后将返回数据交给该实例处理,Event Vertical实例进一步处理数据并将结果返回给浏览器。2. Vert.x-WebVert.x-Web是vert.x的web构建模块。你可以使用它构建现代的可扩展的web应用程序。Vert.x提供了一些相当底层的方式处理HTTP请求,但是对于大多数的应用程序这些也就够用了。Vert.x-Web基于Vert.x-Core为更容易的构建真正的we
3、b应用程序提供了丰富的功能。关于一些Vert.x的关键特征:路由(基于方法、路径等)、正则表达式模式匹配的路径、从路径提取参数、内容协商、请求主体处理、身体大小限制、Cookie解析和处理、多表单上传、多文件上传、子路由器支持、会话支持本地和集群、交叉起源资源共享支持、错误页面处理程序、基本身份验证、基于重定向的身份验证、授权处理程序、JWT基于授权、用户/角色/权限授权、标识处理、服务器端呈现的模板支持(包括支持以下模板引擎的:Handlebars、Jade、MVEL、Thymeleaf)、响应时间处理程序、静态文件服务,包括缓存逻辑和目录清单。请求超时的支持、SockJS支持、事件总线桥大
4、多数的Vert.x的特性被实现为处理事件(Handler),这样你就可以自己实现它。随着时间的推移我们将加入更多特性。这里有一个使用Vert.x核心API编写的hello world的web服务器:HttpServer server = vertx.createHttpServer();server.requestHandler(request - / This handler gets called for each request that arrives on the serverHttpServerResponse response = request.response();respo
5、nse.putHeader(content-type, text/plain);/ Write to the response and end itresponse.end(Hello World!);server.listen(8080);Router 是Vert.x的核心概念之一。它的一个对象可以维护零个或多个路径, 处理请求和调用下一个处理程序:Router router = Router.router(vertx);router.route(“/”).handler(routingContext -/ This handler will be called for every requ
6、estHttpServerResponse response = routingContext.response();Hello World from Vert.x-Web!Route route1 = router.route(/some/path/).handler(routingContext - HttpServerResponse response = routingContext.response(); / enable chunked responses because we will be adding data as / we execute over other handl
7、ers. This is only required once and / only if several handlers do output. response.setChunked(true); response.write(route1n / Call the next matching route after a 5 second delay routingContext.vertx().setTimer(5000, tid - routingContext.next();Route route2 = router.route(route2nRoute route3 = router
8、.route( / This handler will be called for the following request paths: / /some/path / /some/path/ / /some/path/ / /but not: / /some/path/subdirroute3 / Now end the response routingContext.response().end();Route route = router.route().path(/some/path/*route.handler(routingContext - / This handler wil
9、l be called for any path that starts with / /some/path/, e.g. / /some/path/subdir/blah.html / but not: / /some/bath/如果post请求的地址是:/catalogue/products/tools/drill123/ 然后Route会匹配为:productType的值为 tools和productID的值为drill123.Route route = router.route(HttpMethod.POST, /catalogue/products/:productype/:prod
10、uctid/ String productType = routingContext.request().getParam(producttype String productID = routingContext.request().getParam(productid/ Do something with them.server.requestHandler(router:accept).listen(8080);使用阻塞处理程序可以为一个路径(route)添加一个blockingHandler。比如这样:router.route().blockingHandler(routingCont
11、ext - / Do something that might take some time synchronously service.doSomethingThatBlocks(); / Now call the next handler routingContext.next();3. Vert.x中EventBus中的使用event bus 是vert.x的神经系统。每一个vert.x的实例都有一个单一的event bus 实例。它是使用vertx.eventBus()方法获得的。event bus 允许程序中的不同语言编写的模块进行通信,不论他们是相同的vert.x实例,还是不同的v
12、ert.x实例。它甚至可以桥接浏览器中运行的Javascript通信。event bus可以在分布式系统中的多个服务器节点之间进行点对点通信和多个浏览器。event bus支持发布/订阅模式,点对点模式,和请求/响应模式。event bus的API是非常容易的,它主要包括注册消息处理事件,取消处理事件,发送和发布消息。EVENT BUS 的API让我们跳进event bus的API。获得event bus 的对象你可以通过如下代码获得event bus的单一对象:EventBus eb = vertx.eventBus();注册处理事件使用下面这个简单方法注册一个消费处理程序:eb.consu
13、mer(“news.uk.sport”, message -System.out.println(“I have received a message: ” + message.body();当一个消息到达你的处理事件是。你的事件将被激活,并处理这个消息。consumer()方法返回一个MessageConsumer的对象实例。这个对象随后用于注销处理程序,或者用处理程序作为流。然而您也可以使用consumer()返回MessageConsumer没有处理程序,然后单独设置处理程序。例如:MessageConsumer consumer = eb.consumer(“news.uk.sport
14、”);consumer.handler(message -当在集群事件总线上注册一个处理程序时,它可以花一些时间登记到集群的所有节点上。如果你希望在注册完成时得到通知的话,你可以在MessageConsumer上注册一个注册完成的处理程序:pletionHandler(res -if (res.succeeded() System.out.println(“The handler registration has reached all nodes”); else System.out.println(“Registration failed!”);注销处理事件去除处理事件,叫做注销。如果你是
15、集群事件总线, 如果你想当这个过程完成时通知注销,你可以使用下面的方法:consumer.unregister(res -System.out.println(“The handler un-registration has reached all nodes”);System.out.println(“Un-registration failed!发布消息发布消息非常简单,只需要把它发布到指定地址即可:eventBus.publish(“news.uk.sport”, “Yay! Someone kicked a ball”);这一消息将被交付所有订阅news.uk.sport地址处理。发送
16、消息发送消息将导致只有一个注册地址的处理程序接收到消息(多个注册地址也只有一个能收到)。这就是点对点模式,选择处理程序的方法采用非严格循环方式。你可用用send()方法发送一条消息。eventBus.send(“news.uk.sport”, “Yay!未解决的指令包括在-include:override/eventbus_headers.adoc = The Message object你的消息处理程序收到的是一个Message。消息的body对应着是应该发送还是应该发布。消息的headers是可用的。回复消息有时你发送消息后希望得到接收到消息的人的回复。这就需要你使用请求-响应模式。要做到
17、这一点,在消息发送的时候,你可以指定一个回复事件。当你接收到消息的时候,你可以通过调用reply()方法来应答。当这一切发生的时候它会导致一个答复发送回发送方,发送方收到应答消息再做处理。接收方: consumer = eventBus.consumer(“news.uk.sport”);message.reply(“how interesting!发送方: Someone kicked a ball across a patch of grass”, ar -if (ar.succeeded() System.out.println(Received reply: + ar.result()
18、.body(); );对应答也可以做应答。这样你就可以在两个不同的程序中创建一个包含多个回合的对话。发送超时当你发送消息时和指定应答事件时你可以通过DeliveryOptions指定超时时间。如果应答事件不少于超时时间,这个应答事件将失败。默认的超时时间是30S。发送失败消息发送失败的其他原因,包括:没有可用的事件去发送消息接收者已经明确使用失败:失败的消息在所有情况下,应答事件将回复特定的失败。未解决的指令包含在 include:override/eventbus.adoc= Clustered Event Busevent bus 不仅仅存在于一个单一的Vert.x实例中,在一个集群中不同
19、的Vert.x实例也可以形成一个单一的,分布的事件总线。集群编程如果你创建一个Vert.x实例用于集群编程,你需要的得到一个关于集群事件总线配置VertxOptions options = new VertxOptions();Vertx.clusteredVertx(options, res -Vertx vertx = res.result();EventBus eventBus = vertx.eventBus();System.out.println(“We now have a clustered event bus: ” + eventBus);System.out.println
20、(“Failed: ” + res.cause();你应该确保在你的类路径中实现了一个ClusterManager,例如默认的:HazelcastClusterManager。使用命令集群你可以使用命令行运行集群:vertx run my-verticle.js -clusterAutomatic clean-up in verticles4.Vert.x的微服务verticle而Vert.x的verticle本身就是很好的一种服务定义,你可以把verticle看成一个service,也可以把verticle看成一个actor。这样你的视角会切到Actor模型里。本文我们将讨论如何基于Vert
21、.x实现远程调用。Vert.x EventBus两宗罪但Vert.x的EventBus有两点不太好的地方,导致不能原生支持面向接口的服务调用。EventBus是Vert.x的核心,因为它的存在可以使得系统模块化解耦成为可能,同时也可以将业务水平扩展。我们只需要定义EventBus地址然后传入Json对象就可以,所有的事情都很流畅。但是这里有一点不太好的地方,默认传输协议走Json,而Json本身不太好定义数据类型。如果了解Vert.x历史的同学肯定知道为什么EventBus一定要使用Json作为主要的传输对象为了兼容其他JVM上的弱语言。可是现实情况中80%的项目都是基于Java跑的,根本就没
22、有考虑去兼容其他JVM上的语言。这就造成了一种尴尬,大家都传Json对象,然后在Handler里先做一次转换,将Json对象转换成POJO,之后再做业务上的逻辑。这里明显在Handler里做了很多与业务无关的事情,服务定位与对象转换,这些本质上应该是框架层面去解决的。不能隐试的将Json对象转成POJO这是EventBus的一宗罪。(Vert.x3可以直接接受POJO,但是针对一个address,只能接收一种POJO格式。)另外当我们使用EventBus的时候不能很方便的确定方法逻辑,简单的讲我只能EventBus。send()后面跟地址参数以及JSON对象,而这并不适合描述业务,这是Even
23、tBus的二宗罪。举个例子,有一个业务逻辑,对用户的账户进行存款与取款这两个操作,如果用Java接口来描述就很Easy。Java代码interface Account void saveMemory(int total);void withdrawMemory(int total);如果换成EventBus你会发现没办法定义行为的名称(Java的方法),只能通过eb.send(address, json)来调用目标接口。这里的json也许得包含method的描述。这样会显得很啰嗦,关键是对IDE不友好,重构起来不方便,严重影响团队开发流畅度。5. Vertx-RPC介绍介于上面的原因,我们开发
24、了一个简单的RPC框架,它简单的封装了EventBus,使之可以包装成Java的接口。这样客户端与服务端之间调用就像本地接口一样。 vertx-rpc其实做的非常简单,他只依赖protostuff,作为数据传输的协议,当然也可以使用JSON协议。接着只需要定义好接口,然后在服务端实现接口,而客户端只依赖接口,单独将项目打包成jar暴露给出来就可以使用了。我们继续上面的例子,根据接口我们会把项目分成两个Maven模块。SPI,SPI-impl,在parent的pom.xml定义好即可。下面我们先在impl的项目里启动好service并通过EventBus暴露服务。Vertx vertx = Vertx.vertx();String address
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1