Dubbo Refer Service#
简介#
通过两种方式引用远程服务:
使用服务直连的方式引用服务,仅适合在调试或测试服务的场景下使用,不适合在线上环境使用
基于注册中心进行引用
服务引用原理#
Dubbo 服务引用的时机有两个:
饿汉式:在 Spring 容器调用
ReferenceBean的afterPropertiesSet方法时引用服务。可通过配置<dubbo:reference>的init属性开启懒汉式:在
ReferenceBean对应的服务被注入到其他类中时引用。默认情况下,Dubbo 使用懒汉式引用服务
按照 Dubbo 默认配置,整个分析过程从 ReferenceBean 的 getObject 方法开始。
先进行配置检查与收集工作
根据收集到的信息决定服务用的方式,有三种:
引用本地 (JVM) 服务
通过直连方式引用远程服务
通过注册中心引用远程服务
最后都会得到一个
Invoker实例
多个注册中心,多个服务提供者,通过集群管理类
Cluster将多个Invoker合并成一个实例通过代理工厂类 (
ProxyFactory) 为服务接口生成代理类,并让代理类去调用Invoker逻辑
源码分析#
ReferenceBean+getObject(): 服务引用的入口方法
1 处理配置#
ReferenceConfig-init(): 配置解析逻辑
检测
ConsumerConfig实例是否存在,如不存在则创建一个新的实例,然后通过系统变量或dubbo.properties配置文件填充ConsumerConfig的字段。接着是检测泛化配置,并根据配置设置interfaceClass的值从系统属性或配置文件中加载与接口名相对应的配置,并将解析结果赋值给
url字段。url字段的作用一般是用于点对点调用检测几个核心配置类是否为空,为空则尝试从其他配置类中获取
收集各种配置,并将配置存储到
map中处理
MethodConfig实例。该实例包含了事件通知配置解析服务消费者 ip,以及调用
createProxy创建代理对象
2 引用服务#
ReferenceConfig-createProxy(Map<String, String> map): 创建代理对象,调用其他方法构建以及合并 Invoker 实例
本地引用
远程引用
点对点调用
加载注册中心
url
通过
Cluster合并多个Invoker调用
ProxyFactory生成代理类
2.1 创建 Invoker#
Invoker 是 Dubbo 的核心模型,代表一个可执行体。在服务提供方,Invoker 用于调用服务提供类。在服务消费方,Invoker 用于执行远程调用
DubboProtocol
DubboProtocol+refer(Class<T> serviceType, URL url)DubboProtocol-getClients(URL url): 用于获取客户端实例,实例类型为ExchangeClient。ExchangeClient实际上并不具备通信能力,它需要基于更底层的客户端实例进行通信。默认NettyClientDubboProtocol-getSharedClient(URL url): 获取共享客户端DubboProtocol-initClient(URL url): 初始化新的客户端Exchangers+connect(URL url, ExchangeHandler handler): 创建ExchangeClient客户端Exchangers+getExchanger(URL url): 通过 SPI 加载HeaderExchangeClient实例HeaderExchanger+connect(URL url, ExchangeHandler handler):创建
HeaderExchangeHandler对象创建
DecodeHandler对象通过
Transporters构建Client实例创建
HeaderExchangeClient对象
Transporters+connect(URL url, ChannelHandler... handlers)Transporters+getTransporter(): 在运行时根据客户端类型加载指定的Transporter实现类。默认加载NettyTransporter
RegistryProtocol
RegistryProtocol+refer(Class<T> type, URL url)url设置协议头根据
url参数加载注册中心实例获取
group配置,根据group配置决定doRefer第一个参数的类型
RegistryProtocol-doRefer(Cluster cluster, Registry registry, Class<T> type, URL url)创建一个
RegistryDirectory实例,然后生成服务者消费者链接,并向注册中心进行注册注册完毕后,紧接着订阅
providers、configurators、routers等节点下的数据完成订阅后,
RegistryDirectory会收到这几个节点下的子节点信息由于一个服务可能部署在多台服务器上,这样就会在
providers产生多个节点,这个时候就需要Cluster将多个服务节点合并为一个,并生成一个Invoker
2.2 创建代理#
ProxyFactory#getProxy(Invoker<T> invoker)AbstractProxyFactory+getProxy(Invoker<T> invoker, boolean generic): 用来获取interfaces数组JavassistProxyFactory+getProxy(Invoker<T> invoker, Class<?>[] interfaces): 生成Proxy子类(Proxy是抽象类)。并调用Proxy子类的newInstance方法创建Proxy实例InvokerInvocationHandler+InvokerInvocationHandler(Invoker<?> handler): 实现 JDK 的InvocationHandler接口,用于拦截接口类调用Proxy+getProxy(Class<?>... ics): 调用重载方法Proxy+getProxy(ClassLoader cl, Class<?>... ics):ccp: 用于为服务接口生成代理类ccm: 用于为org.apache.dubbo.common.bytecode.Proxy抽象类生成子类
package org.apache.dubbo.common.bytecode;
public class proxy0 implements org.apache.dubbo.demo.DemoService {
public static java.lang.reflect.Method[] methods;
private java.lang.reflect.InvocationHandler handler;
public proxy0() {
}
public proxy0(java.lang.reflect.InvocationHandler arg0) {
handler = $1;
}
public java.lang.String sayHello(java.lang.String arg0) {
Object[] args = new Object[1];
args[0] = ($w) $1;
Object ret = handler.invoke(this, methods[0], args);
return (java.lang.String) ret;
}
}