Dubbo源码|二十二、Dubbo服务引入——服务发现
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第33天,点击查看活动详情
开篇
本文介绍Dubbo服务引入部分的源码分析——服务发现。
服务发现
Dubbo的服务发现是在RegistryProtocol#refer
方法中完成的,关于这个方法的工作流程上一篇已经介绍过了,这里不再赘述,本篇从RegistryProtocol#interceptInvoker
方法开始。
protected <T> Invoker<T> interceptInvoker(ClusterInvoker<T> invoker, URL url, URL consumerUrl) {
List<RegistryProtocolListener> listeners = findRegistryProtocolListeners(url);
if (CollectionUtils.isEmpty(listeners)) {
return invoker;
}
for (RegistryProtocolListener listener : listeners) {
listener.onRefer(this, invoker, consumerUrl);
}
return invoker;
}
该方法首先通过Dubbo SPI
获取RegistryProtocolListener
接口的实现类,然后遍历其所有的实现类,调用实现类的onRefer
方法。RegistryProtocolListener
接口的实现类为MigrationRuleListener
。在onRefer
方法中,处理逻辑也很简单调用MigrationRuleHandler#doMigrate
方法。
doMigrate
方法为迁移规则执行的,该方法有个参数rawRule
,这个参数封装了迁移的配置规则的信息,默认人INIT
,这个配置信息会被解析为MigrationRule
类型。根据MigrationRule
实例的信息,会调用MigrationInvoker#refreshInterfaceInvoker
方法。
刷新接口级服务发现Invoker
public synchronized void refreshInterfaceInvoker() {
clearListener(invoker);
if (needRefresh(invoker)) {
invoker = registryProtocol.getInvoker(cluster, registry, type, url);
if (migrationMultiRegistry) {
setListener(serviceDiscoveryInvoker, () -> {
this.setAddressChanged();
});
}
}
}
该方法处理逻辑如下:
- 清空
invoker
中的服务变更监听器,该监听器是存储在服务目录中的。 - 判断
invoker
对象是否为空或者是否被销毁,如果是的话就需要刷新。 - 调用
getInvoker
方法重新获得invoker
。 - 设置服务监听。
获取invoker
调用registryProtocol.getInvoker
方法重新获取invoker
,还记得registryProtocol
这个对象对应的是什么类吗?对应的是InterfaceCompatibleRegistryProtocol
,这个类是通过DubboSPI
加载进来的。
registry=org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol
service-discovery-registry=org.apache.dubbo.registry.integration.RegistryProtocol
继续看getInvoker
方法,该方法会先初始化一个动态服务目录DynamicDirectory
,然后调用doCreateInvoker
方法来创建invoker
对象。
public <T> ClusterInvoker<T> getInvoker(Cluster cluster, Registry registry, Class<T> type, URL url) {
DynamicDirectory<T> directory = new RegistryDirectory<>(type, url);
return doCreateInvoker(directory, cluster, registry, type);
}
创建invoker
protected <T> ClusterInvoker<T> doCreateInvoker(DynamicDirectory<T> directory, Cluster cluster, Registry registry, Class<T> type) {
directory.setRegistry(registry);
directory.setProtocol(protocol);
Map<String, String> parameters = new HashMap<String, String>(directory.getConsumerUrl().getParameters());
URL urlToRegistry = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
if (directory.isShouldRegister()) {
directory.setRegisteredConsumerUrl(urlToRegistry);
registry.register(directory.getRegisteredConsumerUrl());
}
directory.buildRouterChain(urlToRegistry);
directory.subscribe(toSubscribeUrl(urlToRegistry));
return (ClusterInvoker<T>) cluster.join(directory);
}
该方法的工作流程如下:
- 将注册中心、协议等信息保存到服务目录。
- 从服务目录里获取服务url对应的参数,并去除无用的参数,例如
register.ip
。 - 生成要注册的
url
,此时协议为consumer
。 - 判断是否需要注册,如果服务接口不为
*
并且register
值为true
,就需要注册。 - 将消费者
url
注册到注册中心。 - 根据注册
url
构造路由链。 - 根据注册
url
订阅服务。 - 生成
invoker
并返回。
构造路由链
public void buildRouterChain(URL url) {
this.setRouterChain(RouterChain.buildChain(url));
}
public static <T> RouterChain<T> buildChain(URL url) {
return new RouterChain<>(url);
}
private RouterChain(URL url) {
List<RouterFactory> extensionFactories = ExtensionLoader.getExtensionLoader(RouterFactory.class)
.getActivateExtension(url, ROUTER_KEY);
List<Router> routers = extensionFactories.stream()
.map(factory -> factory.getRouter(url))
.collect(Collectors.toList());
initWithRouters(routers);
}
路由就是我们可以设置一些规则,像网关一样,设置哪些服务提供者可以被哪些消费者调用,也可以对服务的调用进行限制等。
- 通过
DubboSPI
机制获取RouterFactory
接口的实现类,其实现类主要有四个:MockRouterFactory
、TagRouterFactory
、AppRouterFactory
、ServiceRouterFactory
。 - 遍历
RouterFactory
实现类,调用getRouter
方法创建Router
实例; - 对
routers
进行排序。
应用路由
AppRouter
是在AppRouterFactory
类中创建出来的,主要是监听应用级别的配置,例如:dubbo-demo-annotation-consumer.condition-router
。
服务路由
ServiceRouter
是在ServiceRouterFactory
类中创建出来的,主要是监听服务级别的配置,路由key的格式格式为:{interfaceName}:[version]:[group]
,例如:org.apache.dubbo.demo.DemoService:1.0.0:test.condition-router
。
标签路由
TagRouter
是在TagRouterFactory
类中创建出来的,主要是监听服务端的配置,例如:dubbo-demo-annotation-provider.tag-router
。
dubbo-admin
中可以对这些路由进行配置,通过这些配置可以达到服务分流、分组或者其他个性化的定制操作。
后记
下一篇将介绍Dubbo服务引入的服务目录的监听配置,对服务监听做详细介绍。
转载自:https://juejin.cn/post/7182429610423320632