本文基于dubbo 2.7.5版本代码


DubboBootstrap启动过程详解

  • 一、触发DubboBootstrap启动
  • 二、start方法详解
  • 1、initialize方法
  • 2、exportServices方法
  • 3、isOnlyRegisterProvider方法
  • 4、hasExportedServices方法
  • 5、exportMetadataService方法
  • 6、registerServiceInstance方法
  • 7、referServices方法



DubboBootstrap的启动是由start方法完成的,start方法的执行成功,意味着dubbo的启动结束。服务端服务的暴露就是在start方法中完成的。

一、触发DubboBootstrap启动

dubbo启动的时候,将DubboBootstrapApplicationListener注册为监听器,监听ContextRefreshedEvent事件。代码如下:

public void onApplicationContextEvent(ApplicationContextEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            onContextRefreshedEvent((ContextRefreshedEvent) event);
        } else if (event instanceof ContextClosedEvent) {
            onContextClosedEvent((ContextClosedEvent) event);
        }
    }
    //监听ContextRefreshedEvent事件
    private void onContextRefreshedEvent(ContextRefreshedEvent event) {
        dubboBootstrap.start();//调用start方法
    }

从上面代码可以看出,当发生ContextRefreshedEvent事件的时候,dubbo调用DubboBootstrap的start方法。

二、start方法详解

下面分析一下start方法(代码有删减)。

public DubboBootstrap start() {
		//只能初始化一次
        if (started.compareAndSet(false, true)) {
            initialize();//调用初始化方法
            // 1. export Dubbo Services
            exportServices();
            // Not only provider register
            if (!isOnlyRegisterProvider() || hasExportedServices()) {
                // 2. export MetadataService
                exportMetadataService();
                //3. Register the local ServiceInstance if required
                registerServiceInstance();
            }
            referServices();
        }
        return this;
    }

1、initialize方法

在start方法中,也会调用initialize方法,之前提到过,服务端启动的时候,dubbo在start方法中调用initialize方法做初始化,而客户端启动的时候会跳过initialize方法。

2、exportServices方法

initialize方法之后调用exportServices方法,该方法用于暴露服务,服务端使用。

private void exportServices() {
		//创建的每个ServiceConfig对象都添加到configManager,下面获取所有的ServiceConfig对象并遍历
        configManager.getServices().forEach(sc -> {
            // TODO, compatible with ServiceConfig.export()
            ServiceConfig serviceConfig = (ServiceConfig) sc;
            serviceConfig.setBootstrap(this);
            if (exportAsync) {//异步暴露,使用线程池暴露服务
                ExecutorService executor = executorRepository.getServiceExporterExecutor();
                Future<?> future = executor.submit(() -> {
                    sc.export();//暴露服务
                });
                asyncExportingFutures.add(future);
            } else {
                sc.export();//暴露服务,export方法以后文章介绍
                exportedServices.add(sc);//记录所有暴露的服务
            }
        });
    }

3、isOnlyRegisterProvider方法

isOnlyRegisterProvider方法检查ApplicationConfig的registerConsumer属性,从代码分析,registerConsumer只是用于在这里做了判断,我认为该属性无用,可以不用配置。

4、hasExportedServices方法

hasExportedServices()检查是否配置元数据中心的url,如果配置了,返回true。

5、exportMetadataService方法

exportMetadataService方法用于暴露本地元数据服务,在《dubbo解析-DubboBootstrap(二)》的文章里面介绍了方法initMetadataServiceExporter,initMetadataServiceExporter方法里面建立了对象metadataServiceExporter,然后在这里暴露服务。服务暴露后客户端可以使用MetadataService接口方法查看dubbo实例的元数据,服务是以dubbo服务形式发布的。关于MetadataService以后文章介绍。

private void exportMetadataService() {
        metadataServiceExporter.export();
    }

6、registerServiceInstance方法

registerServiceInstance用于将dubbo实例注册到专用于服务发现的注册中心。

private void registerServiceInstance() {
        if (CollectionUtils.isEmpty(getServiceDiscoveries())) {
            return;
        }
        ApplicationConfig application = getApplication();
        String serviceName = application.getName();
        URL exportedURL = selectMetadataServiceExportedURL();
        String host = exportedURL.getHost();
        int port = exportedURL.getPort();
        //创建ServiceInstance对象,该对象中持有下面方法的入参值,以及注册中心的类型,默认是local。ServiceInstance代表了一个dubbo实例,其他dubbo实例可以通过ServiceInstance的属性信息找到本实例的位置
        ServiceInstance serviceInstance = createServiceInstance(serviceName, host, port);
        //获取所有的注册中心,将ServiceInstance对象注册到注册中心,这里的注册中心实现了ServiceDiscovery接口,是专用于服务发现的。
        getServiceDiscoveries().forEach(serviceDiscovery -> serviceDiscovery.register(serviceInstance));
    }

7、referServices方法

referServices方法用于处理ReferenceConfig对象,但是这里有个问题。

private void referServices() {
        if (cache == null) {
            cache = ReferenceConfigCache.getCache();
        }
        configManager.getReferences().forEach(rc -> {
            // TODO, compatible with  ReferenceConfig.refer()
            ReferenceConfig referenceConfig = (ReferenceConfig) rc;
            referenceConfig.setBootstrap(this);

            if (rc.shouldInit()) {
                if (referAsync) {
                    CompletableFuture<Object> future = ScheduledCompletableFuture.submit(
                            executorRepository.getServiceExporterExecutor(),
                            () -> cache.get(rc)
                    );
                    asyncReferringFutures.add(future);
                } else {
                    cache.get(rc);
                }
            }
        });
    }

可以看到,上面的代码遍历的ReferenceConfig对象列表是从configManager中获取的,一般的XXXConfig对象是由spring容器创建的,每个对象都会加入到configManager中(可以查看方法addIntoConfigManager),但是ReferenceConfig对象的创建有点特殊,该对象是由ReferenceBeanBuilder创建的:

protected ReferenceBean doBuild() {
        return new ReferenceBean<Object>();
    }

所以ReferenceConfig对象没有加入到configManager中,因此referServices方法没有任何作用。