前言
前面讲了服务提供方在启动服务的时候会进行服务的发布,启动tcp通信端口,注册到注册中心,监听事件等等
服务消费方在启动的时候也会进行服务的发布:注册到注册中心,开启netty客户端用于调用服务提供方,监听服务列表以及配置变更等。这所有的工作都是在@Reference依赖注入时,创建代理实例时完成的.
1. 代理对象的生成
可以肯定的是@Reference 注入进来的类肯定是一个代理的类,在调用该代理对象的方法时,会走rpc远程调用服务提供方的接口实例的方法。
利用JDK动态代理对有@Reference的接口进行代理
创建InvocationHandler,持有ReferenceBean的引用(就是@Reference里的配置信息)
判断容器中是否有referencedBeanName的实例,如果是@Service注解的类就会在spring容器中,否则就是远程应用的接口,进行InvocationHandler的初始化
InvocationHandler持有一个对象bean,invoke方法里反射调用的其实是这个bean对象的方法
一开始创建InvocationHandler对象时,bean对象肯定没有,需要赋值,调到了referenceBean的get方法
服务消费方启动的所有核心逻辑都在这个ReferceBean的父类的ReferenceConfig.init()方法中
2. ReferenceConfig.init() 消费方启动核心方法
2.1 获取配置
一进来就是检查配置,和服务提供方启动获取配置差不多的逻辑
获取application,module,registries,monitor等配置,registries,monitor配置分别以consumer -> module -> application按优先级进行赋值
consumer,module,application的来源
这些都是对应的配置类的实例,是从spring容器中获取的,然后赋值
`对应的配置信息是怎么变成配置类的bean并注册到spring容器中,可以看【dubbo源码】5.配置信息解析-注解版
2.2 url协议构建
2.1 将配置装到map中
获取到配置之后,把所有的配置都装到一个局部变量map里
获取本机的ip :先是从系统变量获取, 再是读网卡,和服务提供方 读本机ip是一样的,读到了也扔到map中
最后的map是这样的
创建ref的代理
2.2 url协议构建
三种调用方式
- 本地调用
- 点对点调用,@Reference配置url
- 远程调用(经过注册中心)
-
先传入创建一个临时的URL对象
image
-
先判断是不是
本地调用
本地调用指的是不走远程调用,调用本地的服务实例
配置方式:
// injvm=true,表示调用该实例方法不走远程 @Reference(injvm = true) private UserService userService;
image其他就是判断url中有没有injvm=true,url是根据map生成的,map装的是配置信息,就是判断你的injvm配置是否为true
image如果是本地调用,将会生成一个injvm协议url,利用url的协议头
injvm
获取protocol对应的实现类InjvmProtocol的refer()方法进行invoker对象的创建injvm://127.0.0.1/com.lb.dubbo_api.service.UserService?application=dubbo-c&dubo=2.0.2&injvm=true &interface=com.lb.dubbo_api.service.UserService&methods=getUser &pid=7848®ister.ip=192.168.100.72&side=consumer×tamp=1626427621131
image -
先判断是不是
点对点调用
点对点调用指的是在@Reference配置url参数,指定调用这个url主机的服务实例方法
image -
走注册中心
根据注册中心配置,构建registry协议URL,并把当前消费者的配置信息,配置到每一个注册协议中
image-
单注册中心创建一个invoker对象
image -
多注册中心创建多个invoker对象,并包装到StaticDirectory对象中
image
-
2.3 refprotocol.refer(interfaceClass, url) 创建Invoker对象
这个方法很重要,包含了很多功能要点
- 注册consumer
- 监听providers,configurators,routers节点的变化 :
动态修改配置
,刷新服务列表
,路由过滤
等
refprotocol对象的来源 - spi机制
获取到的先是javaassist生成的类,然后refer代码里根据extName获取到的肯定是一个Protocol的包装类对象,并且最里面的实例根据现在的url是注册协议,获取到的会是RegisrtyProtocol ,【dubbo源码】7.dubbo的spi机制源码
跟服务提供方发布时的调用流程差不多
,这三个类具体是干嘛的,可以看这个【dubbo源码】9. 服务提供方发布之netty服务端启动
最后调用到 RegisrtyProtocol的refer方法
在调到dorefer方法
-
消费者注册
comsumer协议
consumer://192.168.100.72/com.lb.dubbo_api.service.UserService?application=dubbo-c&category=consumers&check=false &dubbo=2.0.2&interface=com.lb.dubbo_api.service.UserService&methods=getUser&pid=14024&side=consumer×tamp=1626430401334
往zk里写入协议
imageimage利用zk客户端api往/dubbo/com.lb.dubbo_api.service.UserService/consumers节点下写数据
image通过toUrlPath(url)获取真正要注册到zk的url
// 节点路径 /dubbo/com.lb.dubbo_api.service.UserService/consumers // 节点数据 consumer%3A%2F%2F192.168.100.72%2Fcom.lb.dubbo_api.service.UserService%3F application%3Ddubbo-c%26category%3Dconsumers%26check%3Dfalse%26dubbo%3D2.0.2%26interface%3Dcom.lb.dubbo_api.service.UserService%26 methods%3DgetUser%26pid%3D14024%26side%3Dconsumer%26timestamp%3D1626430401334
查看该zk节点
image