目的:依据网络编程,手写RPC
1 熟悉项目结构:
demo:业务项目
hrpc:底层
client,server,core
2 服务端:
2.1 流程
1.服务注册
2.netty监听端口
3.请求解码 --- 一次解码 二次解码
4.请求处理 --- 对业务方法进行调用
5.响应编码 --- 一次二次编码
主要:服务注册 和 网络处理
和spring集成较难 ,就是常见的集成:扫描包结构
包扫描:
1.需要被调用的接口 --- 自己项目
2.rpc依赖的
2.2 代码流程思路
引导类
1.bootstrap入口:
@config
@postcontrotor
runner
2.runner:
逻辑:服务注册 和 网络处理
注册:需要哪些业务接口注册到注册中心
进行标明 @hrpcservice 方便找到实现类
@hrpcservice 子注解@commpoent
@hrpcservice 属性 排除实现的其他接口
网络:提供编解码器,和对应请求的handel
3.registry:
如何进行交互?向zk写数据
注册接口:
@component
引入zk 客户端 有工具类
涉及读取配置类
回顾:zk 树 dubbo 注册案例
核心:接口 到 IP + port 的映射
zk工具类
1.创建根节点
2.提供者的节点 应该是 临时 节点
创建自己的节点 ,监听机制 --- 监听目录
步骤
找到要暴露的接口信息:
方法:扫描的包路径 --- 麻烦
从容器中获取 --- springboot基于注解获取 bean
先判断 根节点不为空
找到bean :
处理:把这个接口 创建 为持久节点
IP + port 才是要注册到这个持久节点 的 临时 节点/ 一个提供者节点
拿到本机的IP --- networkutil
端口信息:读取配置 configutil
---- 完成服务信息的注册
4.rpcservice --- 网络服务的启动
@component
1 + m + n
阻塞等待监听关闭
或者
不阻塞 , 添加监听
5.编写handel --- core 项目
一次编解码 客户端和 服务端 可以共用
二次不行 请求 VS 响应
5.1 一次编解码
常见的一次编解码器
5.2 二次编解码
请求 解码 继承 MtoM<bytebuf>
proto 序列化框架
从channle 读出来
序列化 出来
响应 编码 --- 服务端 继承 MtoM<bytebuf>
proto 序列化框架
申请 bytebuf
5.3 请求处理器 业务处理的线程池
继承 simpleinbound
可复用 @shareable
找到 具体接口 发起调用
可在容器中找到
3 客户端
代理实现 业务接口
远程调用:从缓存 拿到, 发请求,请求编码,响应解码,响应处理
服务发现:从zk 拿到提供者
服务信息要缓存 哪些需要远程调用, 打标
3.1 代码流程思路
1.boot
runner
2.runner 入口方法
提供.run 方法
任务:
服务发现,代理生成,网络调用
基于接口发现 或者 拉取所有服务
zk的配置信息 --- config util
zk工具类 --- zkclient
缓存: 存到cache --- cache 的接口
3.servicediscovery
服务发现
zkutil.get service list() --- 返回根节点下所有接口服务的实现
如果非空
拿其子节点 的 ip + port,然后 存到缓存
还要 监听 节点的 变化信息
4.如何找到这个标
bean 的 后置处理器 来找到 这个标
动态代理
代理工厂
基于接口 --- JDK的代理
用的是 CJlib代理
实现xxxxaware接口,重写setcontext方法,来拿到代理工厂
5.生成代理
cglibhandel 的 intercept方法
包装请求
接受响应
6.请求管理器
放到容器中
从缓存中拿到目的地
负载均衡
先拿首个
requestbynetty()
netty 编写客户端
只用编写二次编解码器
只用改其中的对象
业务handel
simpleinbound
7.接受结果
准备Promise
准备映射 --- id --- Promise
4 优化
rpc底层基于长连接
复用channel
缓存channel
requestid 在获取结果后 移除
负载均衡:
多个提供者
客户端负载均衡方案
多个实现如何选择 --- 配置 --- 注解