DUBBO源码学习(三)v2.7.8-服务的暴露过程

dubbo源码学习历史文章

DUBBO源码学习(一)spi机制
DUBBO源码学习(二)注册中心源码解析

一、DUBBO服务暴露

spring ioc容器启动的时候会同时启动dubbo容器,从2.7.5版本后增加了DubboBootstrapApplicationListener类,负责监听dubbo容器的启动事件:


/**
 * The {@link ApplicationListener} for {@link DubboBootstrap}'s lifecycle when the {@link ContextRefreshedEvent}
 * and {@link ContextClosedEvent} raised
 *
 * @since 2.7.5
 */
public class DubboBootstrapApplicationListener extends OnceApplicationContextEventListener implements Ordered {
   

    /**
     * The bean name of {@link DubboBootstrapApplicationListener}
     *
     * @since 2.7.6
     */
    public static final String BEAN_NAME = "dubboBootstrapApplicationListener";

    private final DubboBootstrap dubboBootstrap;

    public DubboBootstrapApplicationListener() {
   
        this.dubboBootstrap = DubboBootstrap.getInstance();
    }

    public DubboBootstrapApplicationListener(ApplicationContext applicationContext) {
   
        super(applicationContext);
        this.dubboBootstrap = DubboBootstrap.getInstance();
        DubboBootstrapStartStopListenerSpringAdapter.applicationContext = applicationContext;
    }

    /**
     * Spring ioc 容器事件监听
     * @param event
     */
    @Override
    public void onApplicationContextEvent(ApplicationContextEvent event) {
   
        if (DubboBootstrapStartStopListenerSpringAdapter.applicationContext == null) {
   
            DubboBootstrapStartStopListenerSpringAdapter.applicationContext = event.getApplicationContext();
        }
        //容器刷新事件
        if (event instanceof ContextRefreshedEvent) {
   
            onContextRefreshedEvent((ContextRefreshedEvent) event);

        //容器关闭事件
        } else if (event instanceof ContextClosedEvent) {
   
            onContextClosedEvent((ContextClosedEvent) event);
        }
    }

    private void onContextRefreshedEvent(ContextRefreshedEvent event) {
   
        dubboBootstrap.start();
    }

    private void onContextClosedEvent(ContextClosedEvent event) {
   
        DubboShutdownHook.getDubboShutdownHook().run();
    }

    @Override
    public int getOrder() {
   
        return LOWEST_PRECEDENCE;
    }
}

可以看到DubboBootstrapApplicationListener继承了OnceApplicationContextEventListener类,主要是实现了onApplicationContextEvent 方法,通过此方法监听了同期的刷新与关闭事件,同时也实现了Ordered接口,执行的顺序为最低顺序。

1.1、DUBBO容器的启动

DUBBO容器的启动是由DubboBootstrap来执行的。DubboBootstrap中有比较重要的两个对象,一个是ConfigManager,一个是Environment。
在这里插入图片描述
从上图可以看出,配置加载大概分为两个阶段:

  1. 第一阶段为DubboBootstrap初始化之前,在Spring context启动时解析处理XML配置/注解配置/Java-config 或者是执行API配置代码,创建config bean并且加入到ConfigManager中。
  2. 第二阶段为DubboBootstrap初始化过程,从配置中心读取外部配置,依次处理实例级属性配置和应用级属性配置,最后刷新所有配置实例的属性,也就是属性覆盖。
  • ConfigManager:顾名思义是一个配置中心,有RegistryConfig(注册中心配置)、ConsumerConfig(消费者配置)、ProtocolConfig(协议配置)、ProviderConfig(服务提供者配置)、ApplicationConfig(容器配置)、MonitorConfig(监控中心配置)。
  • Environment:Environment主要处理的与系统配置相关,比如Java系统配置,以及配置中心的配置。

DUBBO容器的启动是通过start方法执行的:

public class DubboBootstrap {
   

	/**
     * Dubbo的启动
     */
    public DubboBootstrap start() {
   
        //通过cas原子操作代替加锁
        if (started.compareAndSet(false, true)) {
   
            ready.set(false);

            //初始化操作
            initialize();
            if (logger.isInfoEnabled()) {
   
                logger.info(NAME + " is starting...");
            }
            
            // Dubbo Services服务暴露
            exportServices();

            // 是否配置了元数据中心的url
            if (!isOnlyRegisterProvider() || hasExportedServices()) {
   
                // export MetadataService 暴露本地的元数据服务
                exportMetadataService();
                // 将本地serviceInstance注册到注册中心
                registerServiceInstance();
            }

            //处理ReferenceConfig对象
            referServices();

            //service异步暴露后的返回处理
            if (asyncExportingFutures.size() > 0) {
   
                new Thread(() -> {
   
                    try {
   
                        this.awaitFinish();
                    } catch (Exception e) {
   
                        logger.warn(NAME + " exportAsync occurred an exception.");
                    }
                    ready.set(true);
                    if (logger.isInfoEnabled()) {
   
                        logger.info(NAME + " is ready.");
                    }
                    //spi机制,获取所有DubboBootstrapStartStopListener,本包下会拿到DubboBootstrapStartStopListenerSpringAdapter类
                    ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
                    //发布DubboBootstrapStatedEvent事件
                    exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));
                }).start();
            } else {
   
                //service同步暴露处理,与上一步类似
                ready.set(true);
                if (logger.isInfoEnabled()) {
   
                    logger.info(NAME + " is ready.");
                }
                ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
                exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));
            }
            if (logger.isInfoEnabled()) {
   
                logger.info(NAME + " has started.");
            }
        }
        return this;
    }
    
    
    /**
     * 暴露服务
     */
    private void exportServices() {
   
        // 创建的每个ServiceConfig对象都添加到configManager,下面获取所有的ServiceConfig对象并遍历
        configManager.getServices().forEach(sc -> {
   
            ServiceConfig serviceConfig = (ServiceConfig) sc;
            serviceConfig.setBootstrap(this);

            //异步暴露,使用线程池暴露服务
            if (exportAsync) {
   
                ExecutorService executor = executorRepository.getServiceExporterExecutor();
                Future<?> future = executor.submit(() -> {
   
                    try {
   
                        //暴露服务的动作
                        exportService(serviceConfig);
                    } catch (Throwable t) {
   
                        logger.error("export async catch error : " + t.getMessage(), t);
                    }
                });
                asyncExportingFutures.add(future);
            } else {
   
                //暴露服务
                exportService(serviceConfig);
            }
        });
    }

    
    private void exportService(ServiceConfig sc) {
   
        if (exportedServices.containsKey(sc.getServiceName())) {
   
            throw new IllegalStateException("There are multiple ServiceBean instances with the same service name: [" +
                    sc.getServiceName() + "], instances: [" +
                    exportedServices.get(sc.getServiceName()).toString() + ", " +
                    sc.toString() + "]. Only one service can be exported for the same triple (group, interface, version), " +
                    "please modify the group or version if you really need to export multiple services of the same interface.");
        }
        //服务暴露
        sc.export();
        //服务暴露后放入缓存,防止重复暴露
        exportedServices.put(sc.getServiceName(), sc);
    }

}

二、serviceConfig服务暴露

在这里插入图片描述
老图新用,可以看到dubbo的十层协议的第二层,就是serviceConfig.export()。通过serviceConfig.export()方法,我们可以将dubbo的服务通过不同的protocol暴露到注册中心中。

public class ServiceConfig<T> extends ServiceConfigBase<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值