Dubbo的服务消费主要包括两个部分。第一大步是ReferenceConfig
类的init
方法调用Protocol
的refer
方法生成Invoker
实例,这是服务消息的关键。第二大步是把Invoker经过动态代理转换成实现用户接口的动态代理引用。这里的Invoker承载了网络链接、服务调用和重试等功能。java
在消费者的配置文件中存在这个代码:apache
<!-- 生成远程服务代理,能够和本地bean同样使用demoService --> <dubbo:reference id="demoService" interface="org.apache.dubbo.demo.DemoService" />
它会生成一个ReferenceBean
,实现了FactoryBean接口,继承了ReferenceConfig,因此ReferenceBean做为dubbo中可以生产对象的工厂Bean,而咱们要引用服务,也就要有一个该服务的对象。服务器
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
服务引用被触发有两个时机:网络
默认状况下,Dubbo使用懒汉式引用服务。若是须要使用饿汉式,可经过配置dubbo:reference的init属性开启。app
由于ReferenceBean实现了FactoryBean接口的getObject()方法,因此在加载bean的时候,会调用ReferenceBean的getObject()方法。异步
ReferenceBean.getObject() ---> ReferenceConfig.get() --> ReferenceConfig.init()
在init()方法中主要有这几步:
(1) 检测本地存根和mock合法性
(2) 添加协议版本、发布版本、时间戳、application、module、consumer、protocol等全部信息到map中。
(3) 单独处理方法配置,设置重试次数配置以及设置该方法对异步配置信息。
(4) 添加消费者ip地址到map
(5)建立代理对象,调用ReferenceConfig.createProxy()
方法。
(6) 生成ConsumerMpdel存入到ApplicationModel中。jvm
以后介绍ReferenceConfig.createProxy()
方法。主要有下面几步:ide
cluster.join()
方法将多个Invoker进行合并成一个Invoker。proxyFactory.getProxy(invoker)
方法。而后介绍RegistryProtocol.refer(Class<T> type, URL url)
方法生成invoker。url
若是是注册中心服务,则直接返回注册中心服务的invoker;若是不是,则先处理组配置,根据组配置来决定Cluster的实现方式,若是有多个组,则使用MergeableCluster,而后调用doRefer(Cluster, Registry, Class, URL)方法。代理
而后介绍doRefer()
方法。
(1) 建立一个RegistryDirectory实例,设置注册中心、协议等信息
(2) 生成服务消费者连接。
(3) 注册消费信息到注册中心。
(4) 订阅该服务下的providers、configurators、routers等节点下的数据。完成订阅后,RegistryDirectory会受到这几个节点下的子节点信息。
(5) 因为一个服务可能部署在多台服务器上,这样就会在providers产生多个节点,这个时候就须要Cluster将多个服务节点合并成一个,并生成一个Invoker.
在RegistryDirectory实现了NotifyListener接口,服务变动会触发这个类回调notify方法,用于从新引用服务。当发起订阅请求时会进行一次数据拉取操做,同时触发RegistryDirectory.nofity()
方法。这是会执行toInvokers()
方法进行Invoker转换。
(1) 根据消费者protocol配置过滤不匹配的协议。
(2) 合并provider端配置数据,好比服务端IP和port等。
(3) 忽略重复推送的服务列表
(4) 使用具体协议建立远程链接,new InvokerDelegate<T>(protocol.refer(serviceType, url), url, providerUrl)
。
具体的Invoker建立是在DubboProtocol.refer()
中实现。Dubbo协议在返回DubboInvoker对象以前会初始化客户端链接对象。
调用DubboProtocol.initClient()方法 -> Exchangers.connect()方法,根据SPI机制加载HeaderExchangeClent,调用connect()方法。而后调用Transporter类的connect()方法,默认是NettyTransporter类。
public class DubboInvoker<T> extends AbstractInvoker<T> { private final ExchangeClient[] clients; private final AtomicPositiveInteger index = new AtomicPositiveInteger(); private final String version; private final ReentrantLock destroyLock = new ReentrantLock(); private final Set<Invoker<?>> invokers;
public abstract class AbstractInvoker<T> implements Invoker<T> { protected final Logger logger = LoggerFactory.getLogger(getClass()); private final Class<T> type; private final URL url; private final Map<String, Object> attachment; private volatile boolean available = true; private AtomicBoolean destroyed = new AtomicBoolean(false);