打造自己的通信框架四——NettyServer搭建
从客户端发出一条消息到服务端接收并处理这条消息,大概可以分成下面的流程
黄色部分为客户端逻辑,蓝色为网络传输,红色为服务端逻辑,本文关注的是服务端逻辑。
将二进制解码为特定格式,将protobuf封装为自定义格式都是这个处理链的一个单元。
在Netty中,ChannelHandler充当了单元,ChannelPipeline充当处理链。处理链的构造如下
标号1,2,3为我们需要关注的逻辑: 1.将二进制数据解码为protobuf -> 2.将protobuf编码为Request -> 3.Request分发执行
在具体实现上对应下面三点
下面我们详解这三个过程
在这一步我们将二进制数据转换成之前定义的Base.Request
这里使用的两个ChannelHandler都是Netty提供的,不过多叙述
在这一步, MessageFactory.createRequest() 根据moduleId和commandId找出具体的Request,并用proto对象去填充数据。再将创建的AbstractMessage传递给下一层
( MessageRegistry稍后解释 )。
这一步将Channel转换为User,将转发的职责交给RequestDispatchService
channel2SessionMap 记录了Channel和User的对应关系。User是客户端的唯一标识,里面记录了客户端的信息,并承载了异步串行无锁化的功能,具体实现后文会详述。
RequestDispatchService也很简单,找到AbstractRequest对应的方法,再通过反射调用去执行。
user.execute(...) 将这条消息放到用户的消息队列去执行
至此,服务端逻辑结束,下面来看一下这个过程中最核心的MessageRegistry
MessageRegistry有两个功能
举个例子
所有AbstractMessage的具体实现,都会带有 @MessageWrapper 注解,以此将具体的Message和moduleId+commandId关联起来,例如
MessageRegistry会扫描类信息,将其关系记录下来。
一个消息必定有一个对应的方法, @MessageHandler 注解标识某个接口中的某些方法是和消息相关联的
MessageRegistry再将这个方法封装一下,和消息关联起来
通过这套机制,打通了从消息接收到执行的一整套逻辑,开发者不需要关注消息是如何处理的,只要定义好必备的东西就好。