Skip to content
This repository was archived by the owner on Feb 4, 2020. It is now read-only.

YBSport web

EchoLZY edited this page Oct 17, 2018 · 3 revisions

YBSport-web

前面说过,很早前就接触了 vert.x ,但是当初只有 ssh 的经验,并且也是照着教程做的,感觉自己提升还是不高。在接触到这个框架的时候,查阅资料是十分困难的, 在国内的环境下感觉学起来很吃力,后来翻墙找了更多的资料学习,不过其实都没有视频学得容易。自己不断尝试,不断地改变思想,让自己去适应异步的氛围,每一步学习都是自己查的资料。 不得不说这样学起来很累,但是真的,提升真的很大。不论是从问题查找,代码风格还是思维方面,都提升了很多。他的性能与支持也没有让我失望,但是自己还是初步入门, 并没有真正领悟到他的核心,还需要不断地努力。

异步处理

多 Verticle 部署

项目开始的时候,深受横向切割的思想影响,所以将他分为了两个 Verticle ,一个作为路由发送 eventBus ,一个接受并处理数据。但是实在自己思想局限,将所有的请求的处理都放在了一个 Verticle 里面,所有的数据处理都放在了一个 Verticle 里,所以造成的结果就是一个 class 十分冗长,甚至一个方法十分冗长。按照横向切割的思想,应该包如下:

loginService
  |—— LaginVerticle
  |—— LoginDbVerticle
infoService
  |—— InfoVerticle
  |—— InfoDbVerticle

...

我觉得我的理解实在不够深刻,一直没有想通有多个Verticle时候如何一起部署。。。而且当时的自己过于急躁,如今看下来结构实在不忍直视。。。而异步中如何处理两个 Verticle 呢?我当初找到的办法是在确认一个部署成功后,再依次部署第二个,如下:

Future<String> dbVerticleDeployment = Future.future();
        vertx.deployVerticle(new ConvertDbVerticle(), dbVerticleDeployment.completer());
        dbVerticleDeployment.compose(id -> {
            Future<String> convertRestVerticleDeployment = Future.future();
            vertx.deployVerticle(
                    ConvertRestVerticle.class.getName(),
                    new DeploymentOptions().setInstances(1),
                    convertRestVerticleDeployment.completer());
            return convertRestVerticleDeployment;
        }).setHandler(ar -> {
            if (ar.succeeded()) {
                startFuture.complete();
            } else {
                startFuture.fail(ar.cause());
            }
        });

而在 Application 中直接部署 Application 即可。但是不够优雅,这是 vertx 的一个官网示例,但是却还是不明白多个 Verticle 如何处理。。。希望大神解答。

配置读取

学习此框架的核心,无非就是 事件驱动异步处理(非阻塞)。我一开始写的时候遇到的一个问题就是思想的转变,使用 vert.x conf 模块进行读取 json 配置文件, 但是由于是异步的,本着学习的思想,不用 jdk 自带的读取配置文件。所以遇到的一个问题就是异步处理不关心他的结果便向下执行,我因此在 stackoverflow 上 提问, 当然并没有很好地解决问题,遇到错误的概率还是很大,不过我还是采纳了他,因为的确给了我一定的思想。后来我依旧没有办法将他读取的方法独立为一个静态方法,所以只有将它放于代码中执行。

ConfigFactory.retriever.getConfig(res -> {
    if (res.succeeded()) {
        JsonObject httpConfig = res.result().getJsonObject("http");
        server.requestHandler(router::accept)
                .listen(httpConfig.getInteger("port"), httpConfig.getString("host"),
                        listenResult -> {
                            if (listenResult.failed()) {
                                LOGGER.error("Http Server failed!" + listenResult.cause());
                            } else {
                                LOGGER.info("Http Server started on " + httpConfig.getString("host") + ":" + httpConfig.getInteger("port") + "!");
                            }
                        });
    } else {
        LOGGER.error("Config get error! Something went wring during getting the config!" + res.cause());
        throw new RuntimeException("Config get error! Something went wring during getting the config");
    }
});

保证执行成功后才执行后面的代码,这是一开始处理异步的方式。

事务管理

可以说这是我这个应用的败笔吧,我没有做事务处理。也就是说涉及到多个sql操作数据的时候,其中一个失败而另外一个成功,会造成数据不统一。不过在我的程序中,没有同时操作数据的sql存在,而是多个查询语句后只有一个数据操作,而我需要对查询出来的数据进行判断后再决定是否操作数据。而在不断的操作数据库的时候又面临回调地狱的问题所所以我选择使用 Future 来避免回调地狱

Future<SQLConnection> connectionFuture = Future.future();
Future<ResultSet> dateFuture = Future.future();
Future<ResultSet> compareFuture = Future.future();
Future<ResultSet> queryFuture = Future.future();
Future<UpdateResult> updateFuture = Future.future();

异步查询数据,然后让每个 Future 接受处理结果,再单独拿出来 setHandler 处理数据,这样就避免了回调地狱。

结果合并

当我在 ConvertDbVerticle 接受 eventBus 接收到数据的时候,我希望返回的 JsonObject 包含多个从数据库查询出来的结果,例如 getInfo 方法中我希望获得 ybsport_typeybsport_buy 表的数据然后合并至 JsonObject 的 reply 之中,但是数据查询是异步的,如何处理呢?我选择使用了 CompositeFuture 的 all 方法进行组合,只有当两个异步查询都成功的时候,才能够执行 all 的回调函数,然后在 all 的回调函数里面为 reply 填充结果即可。

CompositeFuture.all(typeResult, userResult).setHandler(results -> {
    if (results.succeeded()) {
        LOGGER.info("Both results are ready for use!");
        JsonObject t = results.result().resultAt(0);
        JsonObject u = results.result().resultAt(1);
        reply.mergeIn(t);
        reply.mergeIn(u);
        message.reply(reply);
    } else {
        reportQueryError(message, results.cause(), "Both or one result attempt failed!");
    }
});

此时返回过去的 reply 即是一个合并力两个异步查询的结果集了。

日志处理

vert.x 默认使用的日志处理的是 JDK 内置的 JUL ,但是其输出方式我改了好久都不满意,而且资料太少,所以自己引入了他的日志框架,一开始打算引入 slf4j,后来还是使用了 log4j ,不过需要修改他的默认配置,如下:

    System.setProperty("vertx.logger-delegate-factory-class-name",
            "io.vertx.core.logging.Log4j2LogDelegateFactory");

DNS 解析缓慢或错误

由于易班使用的 oauth 接口,我需要跳转到回调页面,但是发现解析他的域名的时候十分缓慢,查询后才发现他使用的 google 的 dns 解析,所以需要禁用他默认的 DNS,使用系统默认的 DNS 解析。

    System.getProperties().setProperty(DISABLE_DNS_RESOLVER_PROP_NAME, "true");

字符串转 JSON 对象

自己当初阅历有限,傻傻的一个属性一个属性的遍历存放,其实应该使用 jackson 来进行更好的处理的,自己写了一个 StringToPojoJson 实在太笨。

Clone this wiki locally