基于Dubbo 3.1,详细介绍了Dubbo服务的发布与引用的源码。
此前我们学习了Dubbo3.1版本的服务引入的总体流程,以及Dubbo服务引用bean的获取以及懒加载原理。当然真正的服务远程引入、以及配置迁移啥的都还没讲,MigrationRuleListener#onRefer方法,该方法才是真正的服务引入入口,MigrationRuleListener以及真正的服务引入的逻辑,我们后面学习现在来学习。
Dubbo 3.x服务引用源码:
- Dubbo 3.x源码(11)—Dubbo服务的发布与引用的入口
- Dubbo 3.x源码(18)—Dubbo服务引用源码(1)
- Dubbo 3.x源码(19)—Dubbo服务引用源码(2)
- Dubbo 3.x源码(20)—Dubbo服务引用源码(3)
- Dubbo 3.x源码(21)—Dubbo服务引用源码(4)
- Dubbo 3.x源码(22)—Dubbo服务引用源码(5)服务引用bean的获取以及懒加载原理
- Dubbo 3.x源码(23)—Dubbo服务引用源码(6)MigrationRuleListener迁移规则监听器
Dubbo 3.x服务发布源码:
- Dubbo 3.x源码(11)—Dubbo服务的发布与引用的入口
- Dubbo 3.x源码(12)—Dubbo服务发布导出源码(1)
- Dubbo 3.x源码(13)—Dubbo服务发布导出源码(2)
- Dubbo 3.x源码(14)—Dubbo服务发布导出源码(3)
- Dubbo 3.x源码(15)—Dubbo服务发布导出源码(4)
- Dubbo 3.x源码(16)—Dubbo服务发布导出源码(5)
- Dubbo 3.x源码(17)—Dubbo服务发布导出源码(6)
文章目录
1 MigrationRuleListener迁移规则监听器
当前版本可用的监听器仅一个MigrationRuleListener,它用于通过动态更改规则来控制迁移行为。MigrationRuleListener的onrefer方法是Dubbo2.x 接口级服务发现与Dubbo3.x应用级服务发现之间迁移的关键。
MigrationRuleListener有两个执行点:
- refer的时候,consumer行为由默认规则决定。在启动consumer执行refer服务引用的时候会根据默认本地规则对invoker执行的迁移。
- 规则更改的时候,根据新接收的规则更改invoker行为。MigrationRuleListener还会从Dubbo配置中心监听动态迁移规则,如果监听到数据更改,还会对所有服务invoker(onRefer的时候会缓存每个invoker)进行新规则迁移。
迁移规则属于consumer应用程序范围。监听器在所有invoker(接口)之间共享,它维持了接口和handler之间的关系。
2 MigrationRuleListener构造器
我们来看看MigrationRuleListener的构造器。构造器中的主要逻辑有两步:
- 从远程配置中心加载规则配置文件,用作初始化规则。并且监听配置中心指定ruleKey的迁移规则,group为DUBBO_SERVICEDISCOVERY_MIGRATION,当规则改变时动态更新规则。
- 加载本地规则文件,进行延迟初始化(默认延迟60s)。本地文件配置方式本质上是一个延时配置通知的方式,本地文件不会影响默认启动方式,当达到延时时间后触发推送一条内容和本地文件一致的通知。这里的延时时间与规则体中的 delay 字段无关联。 本地文件配置方式可以保证启动以默认行为初始化,当达到延时时触发迁移操作,执行对应的检查,避免启动时就以终态方式启动。
public MigrationRuleListener(ModuleModel moduleModel) {
this.moduleModel = moduleModel;
//初始化
init();
}
private void init() {
//规则key 消费者应用名 + “.migration”
this.ruleKey = moduleModel.getApplicationModel().getApplicationName() + ".migration";
//获取Dubbo配置中心
this.configuration = moduleModel.getModelEnvironment().getDynamicConfiguration().orElse(null);
/*
* 1 远程配置中心配置文件加载,用作初始化规则
*/
if (this.configuration != null) {
logger.info("Listening for migration rules on dataId " + ruleKey + ", group " + DUBBO_SERVICEDISCOVERY_MIGRATION);
//监听配置中心指定ruleKey的迁移规则,group为DUBBO_SERVICEDISCOVERY_MIGRATION
configuration.addListener(ruleKey, DUBBO_SERVICEDISCOVERY_MIGRATION, this);
//获取配置中心group为DUBBO_SERVICEDISCOVERY_MIGRATION,key为ruleKey的动态迁移规则
String rawRule = configuration.getConfig(ruleKey, DUBBO_SERVICEDISCOVERY_MIGRATION);
//如果是空的,那么设置为字符串INIT,即默认规则
if (StringUtils.isEmpty(rawRule)) {
rawRule = INIT;
}
//设置规则字符串给rawRule字段
//解析规则字符串为MigrationRule赋给rule字段
setRawRule(rawRule);
} else {
//使用默认配置规则,因为没有配置配置中心
if (logger.isWarnEnabled()) {
logger.warn("Using default configuration rule because config center is not configured!");
}
//设置规则字符串给rawRule字段
//解析规则字符串为MigrationRule赋给rule字
setRawRule(INIT);
}
/*
* 2 本地规则文件延迟初始化
*/
/*
* 获取本地原始规则
* 首先获取JVM参数或者环境变量中指定的dubbo.migration.file,如果用户未指定则尝试加载类路径下的dubbo-migration.yaml文件,默认null
*/
String localRawRule = moduleModel.getModelEnvironment().getLocalMigrationRule();
if (!StringUtils.isEmpty(localRawRule)) {
//通过调度任务线程池,延迟的进行通知
//本地文件配置方式本质上是一个延时配置通知的方式,本地文件不会影响默认启动方式,当达到延时时间后触发推送一条内容和本地文件一致的通知。
//这里的延时时间与规则体中的 delay 字段无关联。 本地文件配置方式可以保证启动以默认行为初始化,当达到延时时触发迁移操作,执行对应的检查,避免启动时就以终态方式启动
localRuleMigrationFuture = moduleModel.getApplicationModel().getFrameworkModel().getBeanFactory()
.getBean(FrameworkExecutorRepository.class).getSharedScheduledExecutor()
.schedule(() -> {
if (this.rawRule.equals(INIT)) {
this.process(new ConfigChangedEvent(null, null, localRawRule));
}
}, getDelay(), TimeUnit.MILLISECONDS);
}
}
2.1 setRawRule设置原始规则
在MigrationRuleListener构造器中,将会设置原始迁移规则,原始迁移规则首先尝试从配置中心获取。如果没有配置中心获取没有配置规则,那么设置原始规则为字符串INIT,随后调用setRawRule初始化原始规则。
setRawRule方法会尝试解析原始规则字符串成为MigrationRule规则对象,这里的解析实际上就是对yaml字符串的解析,解析成为map,然后设置给MigrationRule对应的属性即可。
这里的parsseRule方法有些小问题,首先会判断如果rule==null,那么会调用MigrationRule.getInitRule()方法,该方法会创建一个MigrationRule实例,然后在下面的步骤中,判断如果INIT.equals(rawRule),那么还会调用MigrationRule.getInitRule()方法继续创建一个MigrationRule实例,但最终只会返回一个MigrationRule,因此会创建多余的MigrationRule对象,本人觉得这是没有必要的。
/**
* 设置原始规则
* @param rawRule 原始规则字符串
*/
public void setRawRule(String rawRule) {
this.rawRule = rawRule;
this.rule = parseRule(this.rawRule);
}
/**
* 解析规则
* @param rawRule 原始规则字符串
* @return 迁移规则对象
*/
private MigrationRule parseRule(String rawRule) {
//如果还没有规则,那么初始化一个默认规则,创建一个MigrationRule
MigrationRule tmpRule = rule == null ? MigrationRule.getInitRule() : rule;
//如果原始规则字符串为INIT,即没有规则
if (INIT.equals(rawRule)) {
//那么初始化一个默认规则,创建一个MigrationRule
tmpRule = MigrationRule.getInitRule();
}
//否则,
else {
try {
//解析原始规则字符串成为规则对象
tmpRule = MigrationRule.parse(rawRule);
} catch (Exception e) {
logger.error("Failed to parse migration rule...", e);
}
}
return tmpRule;
}
2.2 MigrationRule迁移规则
目前存在三种迁移状态:FORCE_INTERFACE(强制接口级),APPLICATION_FIRST(应用级优先)、FORCE_APPLICATION(强制应用级)。
- FORCE_INTERFACE:只启用兼容模式下接口级服务发现的注册中心逻辑,调用流量 100% 走原有流程。
- APPLICATION_FIRST:开启接口级、应用级双订阅,运行时根据阈值和灰度流量比例动态决定调用流量走向。
- FORCE_APPLICATION:只启用新模式下应用级服务发现的注册中心逻辑,调用流量 100% 走应用级订阅的地址。
但实际上,还有更详细的规则配置,规则采用 yaml 格式配置,具体配置下参考如下:
key: 消费者应用名(必填)
step: 状态名(必填)
threshold: 决策阈值(默认1.0)
proportion: 灰度比例(默认100)
delay: 延迟决策时间(默认0)
force: 强制切换(默认 false)
interfaces: 接口粒度配置(可选)
- serviceKey: 接口名(接口 + : + 版本号)(必填)
threshold: 决策阈值
proportion: 灰度比例
delay: 延迟决策时间
force: 强制切换
step: 状态名(必填)
- serviceKey: 接口名(接口 + : + 版本号)
step: 状态名
applications: 应用粒度配置(可选)
- serviceKey: 应用名(消费的上游应用名)(必填)
threshold: 决策阈值
proportion: 灰度比例
delay: 延迟决策时间
force: 强制切换
step: 状态名(必填)
详细说明:
- key: 消费者应用名
- step: 状态名(FORCE_INTERFACE、APPLICATION_FIRST、FORCE_APPLICATION)
- threshold: 决策阈值(浮点数,具体含义参考后文)
- proportion: 灰度比例(0~100,决定调用次数比例)
- delay: 延迟决策时间(延迟决策的时间,实际等待时间为 1~2 倍 delay 时间,取决于注册中心第一次通知的时间,对于目前 Dubbo 的注册中心实现次配置项保留 0 即可)
- force: 强制切换(对于 FORCE_INTERFACE、FORCE_APPLICATION 是否不考虑决策直接切换,可能导致无地址调用失败问题)
- interfaces: 接口粒度配置
参考配置示例如下:
key: demo-consumer
step: APPLICATION_FIRST
threshold: 1.0
proportion: 60
delay: 0
force: false
interfaces:
- serviceKey: DemoService:1.0.0
threshold: 0.5
proportion: 30
delay: 0
force: true
step: APPLICATION_FIRST
- serviceKey: GreetingService:1.0.0
step: FORCE_APPLICATION
配置规则如下:
- 配置中心配置文件下发(推荐)
- Key: 消费者应用名 + “.migration”
- Group: DUBBO_SERVICEDISCOVERY_MIGRATION
- 启动参数配置
- 可通过环境变量或者配置中心配置dubbo.application.service-discovery.migration参数设置,允许值范围:FORCE_INTERFACE、APPLICATION_FIRST、FORCE_APPLICATION。
- 本地文件配置
- 本地配置文件路径配置项dubbo.migration.file ,默认值dubbo-migration.yaml
- 配置文件延迟生效时间(毫秒)配置项dubbo.application.migration.delay,默认值60000
详细规则参见文档:https://dubbo.apache.org/zh/docs/v3.0/advanced/migration-invoker/
3 onRefer引用服务时迁移
现在我们看的onRefer方法就是第一个执行点,即服务引用的时候的迁移,大概步骤为:
- 尝试将当前MigrationInvoker以及对应的MigrationRuleHandler存入handlers缓存,并返回migrationRuleHandler,如果已存在缓存则直接返回migrationRuleHandler。handlers缓存用于后续再次更新迁移规则。
- 调用migrationRuleHandler.doMigrate(rule),根据本地默认规则执行迁移。
/**
* MigrationRuleListener的方法
* <p>
* 当订阅服务时执行
*
* @param registryProtocol RegistryProtocol instance
* @param invoker MigrationInvoker
* @param consumerUrl 表示当前接口及其配置的使用者url
* @param registryURL 注册中心协议url
*/
@Override
public void onRefer(RegistryProtocol registryProtocol, ClusterInvoker<?> invoker, URL consumerUrl, URL registryURL) {
//尝试将当前MigrationInvoker以及对应的MigrationRuleHandler存入handlers缓存,并返回migrationRuleHandler,如果已存在缓存则直接返回migrationRuleHandler
MigrationRuleHandler<?> migrationRuleHandler = handlers.computeIfAbsent((MigrationInvoker<?>) invoker, _key -> {
//如果当前MigrationInvoker不在map中
//设置invoker的migrationRuleListener属性
((MigrationInvoker<?>) invoker).setMigrationRuleListener(this);
//返回根据url和表示当前接口及其配置的使用者url构建MigrationRuleHandler
return new MigrationRuleHandler<>((MigrationInvoker<?>) invoker, consumerUrl);
});
/*
* 根据本地默认规则执行迁移
*/
migrationRuleHandler.doMigrate(rule);
}
3.1 MigrationRuleHandler#doMigrate执行迁移
该方法执行迁移规则,默认规则为APPLICATION_FIRST(应用级优先)。当然,也会从配置中心和环境变量中读取dubbo.application.service-discovery.migration配置。
- 如果invoker属于ServiceDiscoveryMigrationInvoker,表示当前采用应用级别的服务引用协议,那么采用 FORCE_APPLICATION,强制应用级调用refreshInvoker方法刷新invoker。这种需要设置注册中心url参数registry-type=service,而默认情况下invoker属于MigrationInvoker,表示当前采用接口级别的服务引用协议,因此会走下面的逻辑。
- 默认的迁移状态 APPLICATION_FIRST(应用级优先)。当然,也会从配置中心读取配置和从环境变量中读取dubbo.application.service-discovery.migration配置。随后获取threshold,可通过配置中心或者migration.threshold参数指定,默认threshold则是-1。
- 根据迁移状态和阈值以及rule调用refreshInvoker方法刷新invoker,这里的rule参数实际上是MigrationRuleListener初始化的rule。
/**
* MigrationRuleHandler的方法
* 执行迁移
*
* @param rule
*/
public synchronized void doMigrate(MigrationRule rule) {
//如果invoker属于ServiceDiscoveryMigrationInvoker,表示当前采用应用级别的服务引用协议,这种需要设置注册中心url参数registry-type=service
//默认情况下,invoker属于MigrationInvoker,表示当前采用接口级别的服务引用协议
if (migrationInvoker instanceof ServiceDiscoveryMigrationInvoker) {
//在手动启动了应用级别服务注册发现模式下,比如注册中心url添加了registry-type=service参数
//那么采用 FORCE_APPLICATION,强制应用级
refreshInvoker(MigrationStep.FORCE_APPLICATION, 1.0f, rule);
return;
}
// initial step : APPLICATION_FIRST
//默认的迁移状态 APPLICATION_FIRST(应用级优先)
MigrationStep step = MigrationStep.APPLICATION_FIRST;
float threshold = -1f;
try {
//获取配置的类型,默认APPLICATION_FIRST
step = rule.getStep(consumerURL);
//获取migration.threshold阈值,默认1.0
threshold = rule.getThreshold(consumerURL);
} catch (Exception e) {
logger.error("Failed to get step and threshold info from rule: " + rule, e);
}
/*
* 刷新invoker
*/
if (refreshInvoker(step, threshold, rule)) {
// 刷新成功更新rule
setMigrationRule(rule);
}
}
4 refreshInvoker刷新invoker
该方法会判断新的规则和此前的规则如果不一致,那么执行迁移规则,切换状态,根据不同的迁移状态调用不同的方法,默认APPLICATION_FIRST,即应用级优先。
- APPLICATION_FIRST,调用migrationInvoker.migrateToApplicationFirstInvoker(newRule)方法。
- FORCE_APPLICATION,调用migrationInvoker.migrateToForceApplicationInvoker(newRule)方法。
- FORCE_INTERFACE,调用migrationInvoker.migrateToForceInterfaceInvoker(newRule)方法。
- 如果迁移成功,那么将参数设置为currentStep和currentThreshold。
接口级MigrationInvoker和应用级ServiceDiscoveryMigrationInvoker对于这三个方法的实现不同。我们后面单独讲解。
/**
* MigrationRuleHandler的方法
*
* 刷新invoker
*
* @param step 迁移状态
* @param threshold 阈值
* @param newRule 新迁移规则
* @return 是否迁移成功
*/
private boolean refreshInvoker(MigrationStep step, Float threshold, MigrationRule newRule) {
if (step == null || threshold == null) {
throw new IllegalStateException("Step or threshold of migration rule cannot be null");
}
MigrationStep originStep = currentStep;
//如果和之前的规则不同,则执行迁移默认情况下初次启动是currentStep为null,currentThreshold为0.0
if ((currentStep == null || currentStep != step) || !currentThreshold.equals(threshold)) {
boolean success = true;
//根据迁移状态执行迁移
switch (step) {
//应用级优先,默认规则
case APPLICATION_FIRST:
migrationInvoker.migrateToApplicationFirstInvoker(newRule);
break;
//强制应用级
case FORCE_APPLICATION:
success = migrationInvoker.migrateToForceApplicationInvoker(newRule);
break;
//强制接口级
case FORCE_INTERFACE:
default:
success = migrationInvoker.migrateToForceInterfaceInvoker(newRule);
}
//如果迁移成功,那么设置为currentStep和currentThreshold
if (success) {
setCurrentStepAndThreshold(step, threshold);
logger.info("Succeed Migrated to " + step + " mode. Service Name: " + consumerURL.getDisplayServiceKey());
report(step, originStep, "true");
} else {
// migrate failed, do not save new step and rule
logger.warn("Migrate to " + step + " mode failed. Probably not satisfy the threshold you set "
+ threshold + ". Please try re-publish configuration if you still after check.");
report(step, originStep, "false");
}
return success;
}
// ignore if step is same with previous, will continue override rule for MigrationInvoker
return true;
}
4.1 migrateToApplicationFirstInvoker应用级优先
4.1.1 MigrationInvoker接口级服务发现
接口级服务发现MigrationInvoker(默认invoker)如果采用应用级优先策略(默认情况),那么将会调用MigrationInvoker#migrateToApplicationFirstInvoker方法进行策略转换迁移。
该方法将会进行接口级别和应用级别的服务双引入,这和此前的服务双导出是对应的,最后会选择首选invoker,引用级别的invoker优先。
/**
* MigrationInvoker的方法
* <p>
* 迁移至应用级优先
*
* @param newRule 新规则
*/
@Override
public void migrateToApplicationFirstInvoker(MigrationRule newRule) {
CountDownLatch latch = new CountDownLatch(0);
/*
* 刷新接口Invoker
* 涉及到消费者注册到注册中心、拉取服务提供者信息转换为invoker,向注册中心订阅服务等操作
* 说白了就是接口级别的服务引入。
*/
refreshInterfaceInvoker(latch);
/*
* 刷新服务发现Invoker
* 应用级别的服务引入
*/
refreshServiceDiscoveryInvoker(latch);
/*
* 计算首选invoker,应用级别的invoker优先
*/
//直接计算首选调用者,不会等到地址通知,当地址稍后通知时,将重新进行计算
calcPreferredInvoker(newRule);
}
4.1.1.1 calcPreferredInvoker计算首选调用者
/**
* MigrationInvoker的方法
* <p>
* 计算首选invoker,应用级别的invoker优先
*
* @param migrationRule 迁移规则
*/
private synchronized void calcPreferredInvoker(MigrationRule migrationRule) {
//如果其中一个应用级invoker或者接口级invoker为null,则说明只有一个能用,那么无需计算首选invoker,直接返回
if (serviceDiscoveryInvoker == null || invoker == null) {
return;
}
//迁移比较
Set<MigrationAddressComparator> detectors = ScopeModelUtil.getApplicationModel(consumerUrl == null ? null : consumerUrl.getScopeModel())
.getExtensionLoader(MigrationAddressComparator.class).getSupportedExtensionInstances();
if (CollectionUtils.isNotEmpty(detectors)) {
// pick preferred invoker 选择首选的调用程序
// the real invoker choice in invocation will be affected by promotion 在调用中真正的调用者选择将受到提升的影响
//主要是比较是否有directory,以及新旧服务提供者invoker占比是否大于等于threshold
if (detectors.stream().allMatch(comparator -> comparator.shouldMigrate(serviceDiscoveryInvoker, invoker, migrationRule))) {
this.currentAvailableInvoker = serviceDiscoveryInvoker;
} else {
this.currentAvailableInvoker = invoker;
}
}
}
4.1.2 ServiceDiscoveryMigrationInvoker应用级服务发现
应用级服务发现ServiceDiscoveryMigrationInvoker(通常需要特别设置,例如设置注册中心url参数registry-type=service)如果采用应用级优先策略,那么将会调用ServiceDiscoveryMigrationInvoker#migrateToApplicationFirstInvoker方法进行策略转换迁移。
该方法将仅会进行应用级别的服务引入,最后会选择引入的invoker作为可用invoker。
/**
* ServiceDiscoveryMigrationInvoker的方法
*
* @param newRule 新规则
*/
@Override
public void migrateToApplicationFirstInvoker(MigrationRule newRule) {
CountDownLatch latch = new CountDownLatch(0);
/*
* 刷新服务发现Invoker
* 应用级别的服务引入
*/
refreshServiceDiscoveryInvoker(latch);
/*
* 设置当前可用invoker,仅仅是服务发现invoker
*/
setCurrentAvailableInvoker(getServiceDiscoveryInvoker());
}
4.2 migrateToForceApplicationInvoker强制应用级
接口级服务发现MigrationInvoker和应用级服务发现ServiceDiscoveryMigrationInvoker如果采用强制应用级策略,那么都将会调用MigrationInvoker#migrateToForceApplicationInvoker方法进行策略转换迁移,也就是说他们的实现是一样的代码。
该方法将仅会进行应用级别的服务引入,最后会选择引入的invoker作为可用invoker。
/**
* MigrationInvoker的方法
*
* 强制应用级
* @param newRule 新规则
* @return
*/
@Override
public boolean migrateToForceApplicationInvoker(MigrationRule newRule) {
CountDownLatch latch = new CountDownLatch(1);
/*
* 刷新服务发现Invoker
* 应用级别的服务引入
*/
refreshServiceDiscoveryInvoker(latch);
//invoker不存在,忽略阈值检查
if (invoker == null) {
// invoker is absent, ignore threshold check
this.currentAvailableInvoker = serviceDiscoveryInvoker;
return true;
}
// wait and compare threshold
//等待并比较阈值
waitAddressNotify(newRule, latch);
//强制规则
if (newRule.getForce(consumerUrl)) {
// force migrate, ignore threshold check
this.currentAvailableInvoker = serviceDiscoveryInvoker;
this.destroyInterfaceInvoker();
return true;
}
//迁移比较
Set<MigrationAddressComparator> detectors = ScopeModelUtil.getApplicationModel(consumerUrl == null ? null : consumerUrl.getScopeModel())
.getExtensionLoader(MigrationAddressComparator.class).getSupportedExtensionInstances();
if (CollectionUtils.isNotEmpty(detectors)) {
if (detectors.stream().allMatch(comparator -> comparator.shouldMigrate(serviceDiscoveryInvoker, invoker, newRule))) {
this.currentAvailableInvoker = serviceDiscoveryInvoker;
this.destroyInterfaceInvoker();
return true;
}
}
// compare failed, will not change state
if (step == MigrationStep.FORCE_INTERFACE) {
destroyServiceDiscoveryInvoker();
}
return false;
}
4.3 migrateToForceInterfaceInvoker强制接口级
4.3.1 MigrationInvoker接口级服务发现
接口级服务发现MigrationInvoker(默认invoker)如果采用强制接口级,那么将会调用MigrationInvoker#migrateToForceApplicationInvoker方法进行策略转换迁移。
该方法将会进行接口级别的服务引入和迁移。
/**
* MigrationInvoker的方法
* <p>
* 强制接口级
*
* @param newRule 新规则
* @return
*/
@Override
public boolean migrateToForceInterfaceInvoker(MigrationRule newRule) {
CountDownLatch latch = new CountDownLatch(1);
/*
* 刷新接口Invoker
* 涉及到消费者注册到注册中心、拉取服务提供者信息转换为invoker,向注册中心订阅服务等操作
* 说白了就是接口级别的服务引入。
*/
refreshInterfaceInvoker(latch);
//serviceDiscoveryInvoker不存在,忽略阈值检查
if (serviceDiscoveryInvoker == null) {
// serviceDiscoveryInvoker is absent, ignore threshold check
this.currentAvailableInvoker = invoker;
return true;
}
//等待并比较阈值
waitAddressNotify(newRule, latch);
//强制规则
if (newRule.getForce(consumerUrl)) {
// force migrate, ignore threshold check
this.currentAvailableInvoker = invoker;
this.destroyServiceDiscoveryInvoker();
return true;
}
//迁移比较
Set<MigrationAddressComparator> detectors = ScopeModelUtil.getApplicationModel(consumerUrl == null ? null : consumerUrl.getScopeModel())
.getExtensionLoader(MigrationAddressComparator.class).getSupportedExtensionInstances();
if (CollectionUtils.isNotEmpty(detectors)) {
if (detectors.stream().allMatch(comparator -> comparator.shouldMigrate(invoker, serviceDiscoveryInvoker, newRule))) {
this.currentAvailableInvoker = invoker;
this.destroyServiceDiscoveryInvoker();
return true;
}
}
// compare failed, will not change state
if (step == MigrationStep.FORCE_APPLICATION) {
destroyInterfaceInvoker();
}
return false;
}
4.3.2 ServiceDiscoveryMigrationInvoker应用级服务发现
应用级服务发现ServiceDiscoveryMigrationInvoker(通常需要特别设置,例如设置注册中心url参数registry-type=service)如果采用强制接口级策略,那么将会调用ServiceDiscoveryMigrationInvoker#migrateToForceApplicationInvoker方法进行策略转换迁移。
该方法将仅会进行应用级别的服务引入,最后会选择引入的invoker作为可用invoker。
/**
* ServiceDiscoveryMigrationInvoker的方法
*
* @param newRule 新规则
* @return
*/
@Override
public boolean migrateToForceInterfaceInvoker(MigrationRule newRule) {
CountDownLatch latch = new CountDownLatch(0);
/*
* 刷新服务发现Invoker
* 应用级别的服务引入
*/
refreshServiceDiscoveryInvoker(latch);
/*
* 设置当前可用invoker,仅仅是服务发现invoker
*/
setCurrentAvailableInvoker(getServiceDiscoveryInvoker());
return true;
}
5 总结
本次我们学习了MigrationRuleListener迁移规则监听器,为什么要学习他呢?除了在Dubbo服务2.x升级到3.x的迁移过程中的作用之外,实际上它内部的refreshInterfaceInvoker和refreshServiceDiscoveryInvoker这两个方法还兼具接口和应用级别的服务注册、引入、订阅、更新的功能。
我们目前正在学习的服务引入,所以说下面我们将进去refreshInterfaceInvoker和refreshServiceDiscoveryInvoker这两个方法,去看看接口和应用级别的服务在dubbo3.1中到底是如何引入的。