大噶好我又来了,没了解过Vert.x的同学可以先看一下上一篇文章。
Vert.xOK, 这次我们来看点新东西。这次我们要做的场景是:发起一个POST请求新建一个User,这个请求提交了一个Json文件到我们的Server,然后Server接受到这个Json之后序列化成了我们定义的Bean。在验证完Json的合法性之后通过集成的RedisClient存入redis。有一些概念我们需要先了解一下:EventBus、Verticle。
首先是EventBus,"eventBus是vertx的神经系统" by 官方文档。eventBus允许我们程序中不同模块互相之间交换数据,而这些模块可以不使用同一种编程语言编写。简单的说就像是一个回转寿司店,不同的模块就是不同桌的客人,但是这些客人都可以在中间环形的传送带上取到自己想食的寿司(寿司师傅也会把捏好的寿司放在传送带上给客人),聪明的你肯定已经发现了这个寿司就是不同模块之间交换的数据,可以是各种类型。但是在vertx中,两个模块之间如果想要交换数据必须指定一个address,就好比你要去xxx寿司店才能吃到xx师傅捏的xx寿司。
接下来是Verticle,Verticle基本可以看作是Akka中的actor-model,但是严格上讲也不是完全相同的实现方式。在vertx中使用verticle可以大幅度的降低并发编程的难度,每一个verticle都是独立的线程,互相之间不共享数据与耦合,我们的一个程序中可以有任意多个verticle实例,每个实例可以负责不同的业务逻辑。既然verticle都是独立线程,那么它们之间是怎么交换数据呢?(你真是太聪明了)当然是使用eventBus啦,比如我们有V1和V2两个verticle,它们两个共同指定了"interesting"这个address,那么V1向这个地址发送数据,V2此时就可以获取到这个数据再进行后续的处理。而这个流程和消息订阅/发布系统是极为相似的,大家可以类比的理解一下。
那么我们开始,首先是定义Bean,PojoBase集成了序列化接口所以我们需要UID(IDE帮我们生成了):
一个单纯的类在编写Verticle之前先来看一下架构:
一共5个verticle从PersistenceVerticle开始看。每个verticle都继承了AbstractVerticle,为了部署每一个实例都需要重写父类的start方法,这里的PersistenceVerticle只是单纯的启动了RedisClientVerticle做了一层解耦:
PersistenceVerticle接下来看RedisClientVerticle:
RedisClientVerticle这一篇我们只用redis最最简单的set和get,所以只需要传一个host地址进去作为参数,通过vertx实例我们启动好了redis客户端然后打一个log美滋滋。还记得eventBus的address吗,之后这个MessageConsumer就是用来处理adress,我们注册newUser和getUser作为eventBus的地址便于接受其他verticle发来的数据,这个数据的类型就是泛型的类型啦。
因为vertx基于netty,所以我们都是用异步的方式来处理所有的逻辑,实现俩handler来完成get和set:
get/set把user类中的id作为redis里的key值,这里拼接了一个"Vertx_X"作为key,value是user的toString的结果。到这里redis的部分基本就完成了,get和set都会返回一个异步的结果,我们通过这个结果来判断是否set/get成功。关于bean的序列化我们在后面讲。
首先我们部署web服务器的verticle:
WebStartVerticle接下来是重写start方法启动httpserver:
启动httpserver这个地方是并发的写法,当httpserver启动后调用future的complete方法完成最终的启动,在startRouter里面设置了几个路由:
启动路由这个地方声明了一个Router对象,BodyHandler是为了用来接受和传递json数据,consumes和produces设置了数据传递的格式,接下来我们处理GET和POST请求:
创建一个user这个地方我另写了一个webhandler类来处理请求,这个createUser方法首先接受routingContext作为参数,这个参数就像是Servlet里面的HttpServletRequest/Response保存了请求和返回的各类信息,第二个参数是Handler<AsyncResult<JsonObect>>类型的,因为我们使用的是异步的写法,返回了一个异步的结果,实现如下:
处理POST请求在Vertx中提供了Json.decode和encode两个方法序列化json数据,第二个参数是要序列化转化的Bean类,这个地方就是转化成User,之后序列化成功后我们把结果封装进异步结果在返回给路由,如果捕获到了异常就封装一个异常返回,当路由得到了成功序列化的user后就发送给事先设置好的address:
发送数据另一端RedisClientVerticle会订阅这个"newUser"的address,当有数据发来的时候就对这个message进行处理,set进redis。
那么getUser同理,首先是路由:
getUser这里用了router的路径参数:id这个写法,接下来是handler:
获取id作为key我们把得到的id作为key封装进异步结果然后传给路由,路由接受到成功结果后发给redis:
getUser是addressRedisClientVerticle取到数据后会进入redis查询,然后reply方法返回查询到的数据:
返回数据到这里主要的逻辑我们就写完了,那么怎么把这两部分统一到一起启动呢?你写一个main同时启动两个verticle啊,是的,我们写一个main:
然后stream操作不懂的赶紧卸载你的jdk6,上次我就说了。
我们把main跑起来试试效果:
RIP然后结果是:
RIP然后我们再get id 2:
RIP完全没有问题,至此就结束啦!
最近还看了Netty,然后工作的原因一直在搞Spring这一块的东西。对比起来看reactive和servlet那一套各有各的好吧,不过我自己还是挺喜欢reactive这套方法的2333。
网友评论