vertx 异步编程指南 step8-使用RxJava进行反应式编程
到目前为止,我们已经使用基于回调的API探索了Vert.x堆栈的各个领域。它只是起作用,并且这种编程模型在很多语言的开发人员中都是众所周知的。然而,它可能会变得有点乏味,特别是当你结合几个事件源或处理复杂的数据流时。
这正是RxJava发挥的作用,Vert.x可以无缝集成它。
注意
|
在本指南中,使用了RxJava 2.x,但Vert.x也适用于RxJava 1.x. RxJava 2.x在Reactive-Streams规范的基础上完全重写。在2.0 wiki页面的不同之处了解更多信息。 |
启用RxJava API
除了基于回调的API之外,Vert.x模块还提供了“Rxified” API。要启用它,首先将vertx-rx-java2
模块添加到Maven POM文件中:
<dependency> <groupId>io.vertx</groupId> <artifactId>vertx-rx-java2</artifactId> </dependency>
Verticle必须进行修改,以便扩展io.vertx.reactivex.core.AbstractVerticle
而不是io.vertx.core.AbstractVerticle
。这有什么不同?前一类扩展后者并暴露一个io.vertx.reactivex.core.Vertx
领域。
io.vertx.reactivex.core.Vertx
定义rxSomething(…)
与基于回调的对应方法等效的额外方法。
让我们来看看MainVerticle
如何更好地了解它在实践中的工作原理:
Single<String> dbVerticleDeployment = vertx.rxDeployVerticle(
"io.vertx.guides.wiki.database.WikiDatabaseVerticle");
该rxDeploy
方法不会将Handler<AsyncResult<String>>
最终参数作为参数。相反,它返回一个Single<String>
。
此外,调用该方法时操作不会启动。它在你订阅时开始Single
。操作完成后,它会发出部署id
或使用a指示问题的原因Throwable
。
按顺序部署Verticle
要最终确定MainVerticle
重构,我们必须确保部署操作按顺序触发并发生:
dbVerticleDeployment
.flatMap(id -> { (1)
Single<String> httpVerticleDeployment = vertx.rxDeployVerticle(
"io.vertx.guides.wiki.http.HttpServerVerticle",
new DeploymentOptions().setInstances(2));
return httpVerticleDeployment;
}) .subscribe(id -> startFuture.complete(), startFuture::fail); (2)
该
flatMap
运营商应用功能的结果dbVerticleDeployment
。它在这里安排的部署HttpServerVerticle
。订阅时开始操作。在成功或错误时,
MainVerticle
开始未来可能完成或失败。
部分“Rxifying” HttpServerVerticle
如果按顺序跟随指南,随时编辑代码,那么HttpServerVerticle
类仍然使用基于回调的API。在您可以使用RxJava API 自然执行异步操作之前,即 同时需要重构HttpServerVerticle
。
导入Vert.x类的RxJava版本
import io.vertx.reactivex.core.AbstractVerticle; import io.vertx.reactivex.core.http.HttpServer; import io.vertx.reactivex.ext.auth.AuthProvider; import io.vertx.reactivex.ext.auth.User; import io.vertx.reactivex.ext.auth.jwt.JWTAuth; import io.vertx.reactivex.ext.auth.shiro.ShiroAuth; import io.vertx.reactivex.ext.web.Router; import io.vertx.reactivex.ext.web.RoutingContext; import io.vertx.reactivex.ext.web.client.WebClient; import io.vertx.reactivex.ext.web.client.HttpResponse; (1) import io.vertx.reactivex.ext.web.codec.BodyCodec; import io.vertx.reactivex.ext.web.handler.*; import io.vertx.reactivex.ext.web.sstore.LocalSessionStore; import io.vertx.reactivex.ext.web.templ.FreeMarkerTemplateEngine; import org.slf4j.Logger; import org.slf4j.LoggerFactory;
我们的
backupHandler()
方法仍然使用HttpResponse
类,所以它必须导入。事实证明,HttpResponse
Vert.x提供的RxJava版本可以作为这种特定情况下的替代品。所述“Rxified”在代码step-8
作为响应类型由lambda表达式推断引导库的文件夹不导入此类。
在“Rxified” vertx
实例上使用委托
要调用一个方法,io.vertx.core.Vertx
当你有一个方法时io.vertx.reactivex.core.Vertx
,调用该getDelegate()
方法。start()
在创建以下实例时需要调整Verticle的方法 WikiDatabaseService
:
- @Override
- public void start(Future<Void> startFuture) throws Exception {
- String wikiDbQueue = config().getString(CONFIG_WIKIDB_QUEUE, "wikidb.queue");
- dbService = io.vertx.guides.wiki.database.WikiDatabaseService.createProxy(vertx.getDelegate(), wikiDbQueue);
同时执行授权查询
在前面的例子中,我们看到了如何使用RxJava操作符和Rxified Vert.x API按顺序执行异步操作。但有时候这种担保不是必需的,或者您只是希望它们为了性能原因而同时运行。
JWT令牌生成过程HttpServerVerticle
就是这种情况的一个很好的例子。要创建令牌,我们需要完成所有授权查询,但查询彼此独立:
- auth.rxAuthenticate(creds).flatMap(user -> {
- Single<Boolean> create = user.rxIsAuthorised("create"); (1)
- Single<Boolean> delete = user.rxIsAuthorised("delete");
- Single<Boolean> update = user.rxIsAuthorised("update");
- return Single.zip(create, delete, update, (canCreate, canDelete, canUpdate) -> { (2)
- return jwtAuth.generateToken(
- new JsonObject()
- .put("username", context.request().getHeader("login"))
- .put("canCreate", canCreate)
- .put("canDelete", canDelete)
- .put("canUpdate", canUpdate),
- new JWTOptions()
- .setSubject("Wiki API")
- .setIssuer("Vert.x"));
- });
- }).subscribe(token -> {
- context.response().putHeader("Content-Type", "text/plain").end(token);
- }, t -> context.fail(401));
Single
创建三个对象,表示不同的授权查询。当三个操作成功完成时,
zip
运算符回调将与结果一起调用。
查询数据库
直接查询
通常,需要单个数据库查询来准备对用户的响应。对于这样简单的情况,JDBCClient
提供rxQueryXXX
和rxUpdateXXX
方法:
- String query = sqlQueries.get(SqlQuery.GET_PAGE_BY_ID);
- JsonArray params = new JsonArray().add(id);
- Single<ResultSet> resultSet = dbClient.rxQueryWithParams(query, params);
使用数据库连接
当直接查询不适合时(例如,当多个查询必须参与相同的事务时),您可以从池中获取数据库连接。所有你需要做的是呼吁rxGetConnection
的JDBCClient
:
Single<SQLConnection> connection = dbClient.rxGetConnection();
该方法返回一个Single<Connection>
您可以轻松转换flatMapXXX
以执行SQL查询的方法:
- connection
- .flatMapCompletable(conn -> conn.rxExecute(sqlQueries.get(SqlQuery.CREATE_PAGES_TABLE)))
但是如果SQLConnection
参考不再可达,我们怎么能释放连接呢?一个简单而方便的方法是close
在doFinally
回调中调用:
- private Single<SQLConnection> getConnection() {
- return dbClient.rxGetConnection().flatMap(conn -> {
- Single<SQLConnection> connectionSingle = Single.just(conn); (1)
- return connectionSingle.doFinally(conn::close); (2)
- });
- }
在获得连接后,我们将其包装成一个
Single
将
Single
被修改,以调用close
一个doFinally
回调
现在我们将getConnection
随时使用我们需要的数据库连接。
缩小回调和RxJava之间的差距
有时,您可能必须将RxJava代码与基于回调的API混合使用。例如,服务代理接口只能用回调来定义,但实现使用Vert.x Rxified API。
在这种情况下,io.vertx.reactivex.SingleHelper.toObserver
类可以适应Handler<AsyncResult<T>>
RxJava SingleObserver<T>
:
- @Override
- public WikiDatabaseService fetchAllPagesData(Handler<AsyncResult<List<JsonObject>>> resultHandler) { (1)
- dbClient.rxQuery(sqlQueries.get(SqlQuery.ALL_PAGES_DATA))
- .map(ResultSet::getRows)
- .subscribe(SingleHelper.toObserver(resultHandler)); (2)
- return this;
- }
fetchAllPagesData
是一种异步服务代理操作,用Handler<AsyncResult<List<JsonObject>>>
回调定义。该
toObserver
方法适用resultHandler
于aSingleObserver<List<JsonObject>>
,以便在发布行列表时调用处理程序。
注意
|
io.vertx.reactivex.CompletableHelper 并io.vertx.reactivex.MaybeHelper 提供适配器Completable 和Maybe 。 |
数据流
RxJava不仅善于组合不同的事件源,而且对数据流也非常有帮助。与Vert.x或JDK未来不同,a Flowable
不仅发布一个事件流,而且还发布一系列事件。它配备了大量的数据操作操作符。
我们可以使用其中的一些来重构fetchAllPages
数据库垂直方法:
- public WikiDatabaseService fetchAllPages(Handler<AsyncResult<JsonArray>> resultHandler) {
- dbClient.rxQuery(sqlQueries.get(SqlQuery.ALL_PAGES))
- .flatMapPublisher(res -> { (1)
- List<JsonArray> results = res.getResults();
- return Flowable.fromIterable(results); (2)
- })
- .map(json -> json.getString(0)) (3)
- .sorted() (4)
- .collect(JsonArray::new, JsonArray::add) (5)
- .subscribe(SingleHelper.toObserver(resultHandler));
- return this;
- }
与
flatMapPublisher
我们将创建一个Flowable
从发射的项目Single<Result>
。fromIterable
将数据库结果Iterable
转换为Flowable
发出数据库行项目。由于我们只需要页面名称,我们可以将
map
每一JsonObject
行记录到第一列。客户希望数据
sorted
按字母顺序排列。事件巴士服务答复包含在一个单一的
JsonArray
。collect
创建一个新的JsonArray::new
项目,随后添加项目JsonArray::add
。
vertx 异步编程指南 step8-使用RxJava进行反应式编程的更多相关文章
- Apache Spark 2.2.0 中文文档 - Structured Streaming 编程指南 | ApacheCN
Structured Streaming 编程指南 概述 快速示例 Programming Model (编程模型) 基本概念 处理 Event-time 和延迟数据 容错语义 API 使用 Data ...
- RxJava(一):响应式编程与Rx
一,响应式编程 响应式编程是一种关注于数据流(data streams)和变化传递(propagation of change)的异步编程方式. 1.1 异步编程 传统的编程方式是顺序执行的,必须在完 ...
- 响应式编程库RxJava初探
引子 在读 Hystrix 源码时,发现一些奇特的写法.稍作搜索,知道使用了最新流行的响应式编程库RxJava.那么响应式编程究竟是怎样的呢? 本文对响应式编程及 RxJava 库作一个初步的探索. ...
- Swift 响应式编程 浅析
这里我讲一下响应式编程(Reactive Programming)是如何将异步编程推到一个全新高度的. 异步编程真的很难 大多数有关响应式编程的演讲和文章都是在展示Reactive框架如何好如何惊人, ...
- SpringBoot 2.x (14):WebFlux响应式编程
响应式编程生活案例: 传统形式: 一群人去餐厅吃饭,顾客1找服务员点餐,服务员把订单交给后台厨师,然后服务员等待, 当后台厨师做好饭,交给服务员,经过服务员再交给顾客1,依此类推,该服务员再招待顾客2 ...
- Reactive UI -- 反应式编程UI框架入门学习(一)
推荐一个反应式编程的MVVM跨平台框架. 反应式编程 反应式编程是一种相对于命令式的编程范式,由函数式的组合声明来构建异步数据流.要理解这个概念,可以简单的借助Excel中的单元格函数. 上图中,A1 ...
- 函数响应式编程(FRP)—基础概念篇
原文出处:http://ios.jobbole.com/86815/. 一函数响应式编程 说到函数响应式编程,就不得不提到函数式编程,他们俩有什么关系呢?今天我们就详细的解析一下他们的关系. 现在下面 ...
- jQuery编程基础精华01(jQuery简介,顶级对象$,jQuery对象、Dom对象,链式编程,选择器)
jQuery简介 什么是jQuery? jQuery就是一个JavaScript函数库,没什么特别的.(开源)联想SQLHelper类 jQuery能做什么?jQuery是做什么的? jQuery本身 ...
- iOS开发技巧系列---使用链式编程和Block来实现UIAlertView
UIAlertView是iOS开发过程中最常用的控件之一,是提醒用户做出选择最主要的工具.在iOS8及后来的系统中,苹果更推荐使用UIAlertController来代替UIAlertView.所以本 ...
随机推荐
- linux 广播和组播
广播和组播 广播,必须使用UDP协议,是只能在局域网内使用,指定接收端的IP为*.*.*.255后,发送的信息,局域网内的所有接受端就能够接到信息了. 广播的发送端代码 #include <st ...
- C语言三种参数传递方式
值传递.指针传递.引用传递 只有在函数调用时,才会为形参分配内存空间,调用结束便会释放. 值传递和指针传递,传递的都是实参的一份拷贝. C语言在线编译器:http://www.dooccn.com/c ...
- 学习CNN系列二:训练过程
卷积神经网络在本质上是一种输入到输出的映射,它能够学习大量的输入与输出之间的映射关系,而不需要任何输入和输出之间精确的数学表达式,只要用已知的模式对卷积神经网络加以训练,网络就具有输入.输出之间映射的 ...
- 201871010126 王亚涛 《面向对象程序设计(Java)》第八周实验总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- robotframework + appium实例
Open Application http://localhost:4723/wd/hub platformName=Android platformVersion=4.4.2 deviceName= ...
- git push origin master错误
以下错误是因为远程有的文件,本地没有,故而无法push文件到远程 $ git push origin master To git@github.com:AntonioSu/learngitWindow ...
- day16_7.18 常用模块
一.collections collections模块中提供了除了dict,list,str等数据类型之外的其他数据类型:Counter.deque.defaultdict.namedtuple和Or ...
- (day48作业)jQuery+Bootstrap练习题
目录 一.图书管理系统页面搭建 二.jQuery练习题 一.图书管理系统页面搭建 <!DOCTYPE html> <html lang="en"> < ...
- 语音识别:从 WaveNet 到 Tacotron,再到 RNN-T
从 WaveNet 到 Tacotron,再到 RNN-T 谷歌再获语音识别新进展:利用序列转导来实现多人语音识别和说话人分类 雷锋网 AI 科技评论按:从 WaveNet 到 Tacotron,再到 ...
- wait函数和waitpid的使用和总结
wait和waitpid出现的原因 SIGCHLD --当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止) --子进程退出时,内 ...