Dubbo服务发布源码分析

Dubbo通过Springboot自动装配原理,将ServiceBean类注入到Spring容器中,并通过ServiceBean对象来发布服务。

服务发布入口ServiceBean

这里的泛型T指的是各个需要被暴露出的接口类。通过DubboAutoConfiguration自动装配类里的ServiceAnnotationBeanPostProcessor去扫描基础路径并构建成一个个待暴露的ServiceBean类。

public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean,
        ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware,
        ApplicationEventPublisherAware {
   

ServiceBean实现了Spring的事件监听器ApplicationListener并监听上下文刷新事件。当Spring容器启动完成后,会发送对应的上下文刷新事件。当每个ServiceBean接收到对应的上下文刷新事件时,就会执行对应的onApplicationEvent方法。

@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
   
     if (!isExported() && !isUnexported()) {
   
         if (logger.isInfoEnabled()) {
   
             logger.info("The service ready on spring started. service: " + getInterface());
         }
         // 服务暴露
         export();
     }
 }

首先判断该服务是否已经完成服务暴露。没有,则调用ServiceConfig父类的export方法。

public synchronized void export() {
   
    // 检查配置
    checkAndUpdateSubConfigs();

    if (!shouldExport()) {
   
        return;
    }

    if (shouldDelay()) {
   
        DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
    } else {
   
        doExport();
    }
}

在服务暴露之前,检查配置以及判断是否需要延迟服务暴露,最终通过doExport方法做真正的服务暴露操作。

我们进入doExport方法

protected synchronized void doExport() {
   
    if (unexported) {
   
        throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!");
    }
    if (exported) {
   
        return;
    }
    exported = true;

    if (StringUtils.isEmpty(path)) {
   
        path = interfaceName;
    }
    doExportUrls();
}

进入doExportUrls方法

private void doExportUrls() {
   
    // 拼接配置的注册中心URL
    List<URL> registryURLs = loadRegistries(true);
    for (ProtocolConfig protocolConfig : protocols) {
   
        String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);
        // 标注服务已经导出
        ProviderModel providerModel = new ProviderModel(pathKey, ref, interfaceClass);
        ApplicationModel.initProviderModel(pathKey, providerModel);
        doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    }
}

loadRegistries()方法实际上是拼接我们在项目中(bootstrap.yaml)等配置文件中配置了dubbo.register的配置信息。

结果例如:
registry://127.0.0.1:8848/org.apache.dubbo.registry.RegistryService?application=test-provider&dubbo=2.0.2&pid=27976&qos.enable=false&registry=nacos&release=2.7.3&timestamp=1598156456239

附上loadRegistries方法

protected List<URL> loadRegistries(boolean provider) {
   
   // check && override if necessary
   List<URL> registryList = new ArrayList<URL>();
   if (CollectionUtils.isNotEmpty(registries)) {
   
       for (RegistryConfig config : registries) {
   
           // 获取注册地址
           // nacos://127.0.0.1:8848
           String address = config.getAddress();
           // 如果为空,则取0.0.0.0
           if (StringUtils.isEmpty(address)) {
   
               address = ANYHOST_VALUE;
           }
           if (!RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
   
               Map<String, String> map = new HashMap<String, String>();
               appendParameters(map, application);
               appendParameters(map, config);
               map.put(PATH_KEY, RegistryService.class.getName());
               appendRuntimeParameters(map);
               // 如果没有指定服务调用协议类型,则默认为dubbo协议
               if (!map.containsKey(PROTOCOL_KEY)) {
   
                   map.put(PROTOCOL_KEY, DUBBO_PROTOCOL);
               }
               // 将Map转换为URL的形式
               List<URL> urls = UrlUtils.parseURLs(address, map);

               for (URL url : urls) {
   
                   url = URLBuilder.from(url)
                           .addParameter(REGISTRY_KEY, url.getProtocol())
                           .setProtocol(REGISTRY_PROTOCOL)
                           .build();
                   if ((provider && url.getParameter(REGISTER_KEY, true))
                           || (!provider && url.getParameter(SUBSCRIBE_KEY, true))) {
   
                       registryList.add(url);
                   }
               }
           }
       }
   }
   return registryList;
}

回到doExportUrls方法中,进入doExportUrlsFor1Protocol方法。

ServiceConfig.doExportUrlsFor1Protocol

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
   
    String name = protocolConfig.getName();
    if (StringUtils.isEmpty(name)) {
   
        name = DUBBO;
    }

    Map<String, String> map = new HashMap<String, String>();
    map.put(SIDE_KEY, PROVIDER_SIDE);

    appendRuntimeParameters(map);
    appendParameters(map, metrics);
    appendParameters(map, application);
    appendParameters(map, module);
    // remove 'default.' prefix for configs from ProviderConfig
    // appendParameters(map, provider, Constants.DEFAULT_KEY);
    appendParameters(map, provider);
    appendParameters(map, protocolConfig);
    appendParameters(map, this);
    if (CollectionUtils.isNotEmpty(methods)) {
   
        for (MethodConfig method : methods) {
   
            appendParameters(map, method, method.getName());
            String retryKey = method.getName() + ".retry";
            if (map.containsKey
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值