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
实际上并不具备通信能力,它需要基于更底层的客户端实例进行通信。默认NettyClient
DubboProtocol-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;
}
}