设为首页 加入收藏

TOP

dubbo源码阅读之服务导出(一)
2019-09-17 16:21:59 】 浏览:114
Tags:dubbo 源码 阅读 服务 导出

dubbo服务导出

常见的使用dubbo的方式就是通过spring配置文件进行配置。例如下面这样

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo
       http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <dubbo:application name="helloService-provider"/>
    <dubbo:registry address="zookeeper://localhost:2181"/>
    <dubbo:reference interface="com.zhuge.learn.dubbo.services.HelloService"
                     check="false" id="helloService">
        <dubbo:method name="sayHello" retries="2"/>
    </dubbo:reference>

</beans>

spring对于非默认命名空间的标签的解析是通过NamespaceHandlerResolver实现的,NamespaceHandlerResolver也算是一种SPI机制,通过解析jar包中的META-INF/spring.handlers文件,将所有的NamespaceHandler实现类以k-v的形式解析出来并放到内存中。所以要想扩展spring的命名空间,就要实现一个NamespaceHandler。
dubbo实现了自己的命名空间,对应的NamespaceHandler实现类是com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler。这个类也很简单,就是定义了用于解析不同标签的BeanDefinition解析类。但是dubbo的实现稍有不同,它将所有标签的解析都放到同一个类同一个方法中,个人认为这种设计欠妥,不利于扩展新的标签。

如果我们要创建一个服务提供者,我们需要在配置文件中配置service标签,所以dubbo的服务导出一定与这个标签相关。查看DubboNamespaceHandler代码会发现,服务导出的逻辑主要是由ServiceBean实现的,所以接下来我们就以ServiceBean为入口,一步步来分析dubbo的服务导出过程。

ServiceBean概览

ServiceBean继承了ServiceConfig类,同时实现了一大堆接口,这些接口基本上都与spring框架相关。其中ApplicationListener 接口会监听ContextRefreshedEvent事件,这个事件是在spring容器完成刷新后发布的,导出逻辑的入口就在onApplicationEvent方法中。

onApplicationEvent

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()) {
        // 延迟导出服务
        delayExportExecutor.schedule(this::doExport, delay, TimeUnit.MILLISECONDS);
    } else {
        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 registryURLs = loadRegistries(true);
// 如果配置了多个协议,那么每种协议都要导出,并且是对所有可用的注册url进行注册
for (ProtocolConfig protocolConfig : protocols) {
// 拼接服务名称,这里的path一般就是服务名
String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);
// 服务提供者模型,用于全面描述服务提供者的信息
ProviderModel providerModel = new Provi

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/10/10
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇dubbo源码阅读之SPI 下一篇好的学习带给我什么

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目