Introduction to the

This article to analyze the Dubbo launch of the execution process, just do a simple analysis, for the specific source code analysis to do a simple comb (specific analysis of the length of Mrs. Too long…) . Dubbo service is started during the Spring container startup process, Dubbo events and listeners are registered with the Spring container, and Dubbo service is started during the event refresh process. Dubbo service start entry method is DubboBootstrapApplicationListener onApplicationContextEvent method. OnApplicationContextEvent is an incident response method, this method can be carried after receiving the Spring context refresh event Dubbo service start operation, this method is as follows:

Source code analysis

public void onApplicationContextEvent(ApplicationContextEvent event) {
        // Determine the event type, context refresh event
        if (event instanceof ContextRefreshedEvent) {
            // Start the dubbo service here
            onContextRefreshedEvent((ContextRefreshedEvent) event); 
            
            // Context-closing events
        } else if (event instanceof ContextClosedEvent) {
            // Execute the dubbo service shutdown hereonContextClosedEvent((ContextClosedEvent) event); }}private void onContextRefreshedEvent(ContextRefreshedEvent event) {
        dubboBootstrap.start();
    }
​
    private void onContextClosedEvent(ContextClosedEvent event) {
        dubboBootstrap.stop();
    }
​
Copy the code

You can see from the above method that Dubbo starts execution in a Spring context refresh event and closes Dubbo in a Spring context shutdown event.

DubboBoostrap start

public DubboBootstrap start(a) {
    if (started.compareAndSet(false.true)) {
        ready.set(false);
        / / initialization
        initialize();
      
        Export the dubbo service
        exportServices();
​
        // Not just service provider registration
        if(! isOnlyRegisterProvider() || hasExportedServices()) {// 2. Export metadata services
            exportMetadataService();
            // 3. If necessary, register the local ServiceInstance
            registerServiceInstance();
        }
        // Process references to the Dubbo service
        referServices();
        
        // Asynchronous export
        if (asyncExportingFutures.size() > 0) {
            new Thread(() -> {
                try {
                    this.awaitFinish();
                } catch (Exception e) {
                    logger.warn(NAME + " exportAsync occurred an exception.");
                }
                // Set the startup state
                ready.set(true);
            }).start();
          // Non-asynchronous export
        } else {
            // Set the startup state
            ready.set(true); }}return this;
}
Copy the code

This is the DubboBootstrap startup process.

Initialize the

public void initialize(a) {
    if(! initialized.compareAndSet(false.true)) {
        return;
    }

    // Initialize the framework extension
    ApplicationModel.initFrameworkExts();

    // Start the configuration center
    startConfigCenter();

    // Load the remote call configuration
    loadRemoteConfigs();

    // Verify the general configuration
    checkGlobalConfigs();

    / / @ since 2.7.8
    // Start the metadata center
    startMetadataCenter();

    // Initialize the metadata service
    initMetadataService();

    // Initialize the metadata service export
    initMetadataServiceExports();

    // Initialize the event listener
    initEventListener();

    if (logger.isInfoEnabled()) {
        logger.info(NAME + " has been initialized!"); }}Copy the code
Initialize the framework extension
public static void initFrameworkExts(a) {
    // Get an instance of the extended class from ExtensionLoader
    Set<FrameworkExt> exts = ExtensionLoader.getExtensionLoader(FrameworkExt.class).getSupportedExtensionInstances();
    for (FrameworkExt ext : exts) {
        // Initialize FrameworkExtext.initialize(); }}Copy the code

The method through the Dubbo SPI load META-INF/dubbo/internal/org.apache.dubbo.com mon. Context. FrameworkExt file, obtain after the extension and perform its initialization.

Start the Configuration Center
private void startConfigCenter(a) {
​
    // If the configuration center is not set in environment and ConfigManager, and RegistryConfig is added to ConfigManager, set Registry in ConfigManager to the configuration center
    useRegistryAsConfigCenterIfNecessary();
​
    // Get the configuration center
    Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();
​
    // Verify the configuration center
    if (CollectionUtils.isEmpty(configCenters)) {
        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
        / / refresh ConfigCenterConfig
        configCenterConfig.refresh();
        if (configCenterConfig.isValid()) {
            // Add configuration centerconfigManager.addConfigCenter(configCenterConfig); configCenters = configManager.getConfigCenters(); }}else {
        for (ConfigCenterConfig configCenterConfig : configCenters) {
            // Refresh the configuration center
            configCenterConfig.refresh();
            // Verify the configuration center configurationConfigValidationUtils.validateConfigCenterConfig(configCenterConfig); }}if (CollectionUtils.isNotEmpty(configCenters)) {
        // An instance of the multi-configuration center management class
        CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();
        for (ConfigCenterConfig configCenter : configCenters) {
            // Add the configuration center to the multi-configuration center manager
            compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));
        }
        environment.setDynamicConfiguration(compositeDynamicConfiguration);
    }
    // Refresh all configurations
    configManager.refreshAll();
}
Copy the code

The code logic for starting the configuration center is very clear. The code is divided into: Obtain ConfigCnenterConfig, refresh the configuration center, manage multiple configuration centers, and refresh all configurations

Load the remote call configuration
private void loadRemoteConfigs(a) {
    // Convert Registry IDS to RegistryConfig
    List<RegistryConfig> tmpRegistries = new ArrayList<>();
    Set<String> registryIds = configManager.getRegistryIds();
    registryIds.forEach(id -> {
        if (tmpRegistries.stream().noneMatch(reg -> reg.getId().equals(id))) {
            tmpRegistries.add(configManager.getRegistry(id).orElseGet(() -> {
                RegistryConfig registryConfig = new RegistryConfig();
                registryConfig.setId(id);
                // Refresh the registration configuration
                registryConfig.refresh();
                returnregistryConfig; })); }});// Add registration configuration (RegistryConfig)
    configManager.addRegistries(tmpRegistries);
​
    // Convert protocol IDS to ProtocolConfig
    List<ProtocolConfig> tmpProtocols = new ArrayList<>();
    Set<String> protocolIds = configManager.getProtocolIds();
    protocolIds.forEach(id -> {
        if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) {
            tmpProtocols.add(configManager.getProtocol(id).orElseGet(() -> {
                ProtocolConfig protocolConfig = new ProtocolConfig();
                protocolConfig.setId(id);
                / / protocolConfig refresh
                protocolConfig.refresh();
                returnprotocolConfig; })); }});// Add a protocol configuration (ProtocolConfig)
    configManager.addProtocols(tmpProtocols);
}
Copy the code

The method to load the remote generic configuration does two things: convert Registry IDS to RegsitryConfig and refresh, and convert Protocol IDS to ProtocolConfig and refresh.

Verifying common configuration
private void checkGlobalConfigs(a) {
    // Verify ApplicationConfig.
    ConfigValidationUtils.validateApplicationConfig(getApplication());
​
    // Verify MetadataReportConfig(metadata export configuration)
    Collection<MetadataReportConfig> metadatas = configManager.getMetadataConfigs();
    if (CollectionUtils.isEmpty(metadatas)) {
        MetadataReportConfig metadataReportConfig = new MetadataReportConfig();
        / / refresh
        metadataReportConfig.refresh();
        if(metadataReportConfig.isValid()) { configManager.addMetadataReport(metadataReportConfig); metadatas = configManager.getMetadataConfigs(); }}if (CollectionUtils.isNotEmpty(metadatas)) {
        for (MetadataReportConfig metadataReportConfig : metadatas) {
            / / refresh
            metadataReportConfig.refresh();
            / / checkConfigValidationUtils.validateMetadataConfig(metadataReportConfig); }}// Verify ProviderConfig(provider configuration)
    Collection<ProviderConfig> providers = configManager.getProviders();
    if (CollectionUtils.isEmpty(providers)) {
        configManager.getDefaultProvider().orElseGet(() -> {
            ProviderConfig providerConfig = new ProviderConfig();
            configManager.addProvider(providerConfig);
            / / refresh
            providerConfig.refresh();
            return providerConfig;
        });
    }
    for (ProviderConfig providerConfig : configManager.getProviders()) {
        ConfigValidationUtils.validateProviderConfig(providerConfig);
    }
    // Verify ConsumerConfig(consumer configuration)
    Collection<ConsumerConfig> consumers = configManager.getConsumers();
    if (CollectionUtils.isEmpty(consumers)) {
        configManager.getDefaultConsumer().orElseGet(() -> {
            ConsumerConfig consumerConfig = new ConsumerConfig();
            configManager.addConsumer(consumerConfig);
            consumerConfig.refresh();
            return consumerConfig;
        });
    }
    for (ConsumerConfig consumerConfig : configManager.getConsumers()) {
        ConfigValidationUtils.validateConsumerConfig(consumerConfig);
    }
​
    // Verify MonitoryConfig
    ConfigValidationUtils.validateMonitorConfig(getMonitor());
    / / check MetricsConfig
    ConfigValidationUtils.validateMetricsConfig(getMetrics());
    / / check ModuleConfig
    ConfigValidationUtils.validateModuleConfig(getModule());
    / / check SslConfig
    ConfigValidationUtils.validateSslConfig(getSsl());
}
Copy the code

General configuration verification, They are ApplicationConfig, MetadataReportConfig, ProviderConfig, ConsumerConfig, MonitoryConfig, MetricsConfig, ModuleConfig, and SslCon FIG.

Start the metadata service
private void startMetadataCenter(a) {
​
    // Use Registry as the metadata center if necessary
    useRegistryAsMetadataCenterIfNecessary();
​
    ApplicationConfig applicationConfig = getApplication();
​
    String metadataType = applicationConfig.getMetadataType();
    // FIXME, multiple metadata config support.
    Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();
    if (CollectionUtils.isEmpty(metadataReportConfigs)) {
        if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {
            throw new IllegalStateException("No MetadataConfig found, you must specify the remote Metadata Center address when 'metadata=remote' is enabled.");
        }
        return;
    }
    MetadataReportConfig metadataReportConfig = metadataReportConfigs.iterator().next();
    / / check
    ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);
    if(! metadataReportConfig.isValid()) {return;
    }
    / / initialization
    MetadataReportInstance.init(metadataReportConfig.toUrl());
}
Copy the code

Specify MetadataReportConfig and initialize it.

Initialize the metadata service
private void initMetadataService(a) {
    this.metadataService = WritableMetadataService.getExtension(getMetadataType());
}
Copy the code

Get MetadataService via Dubbo SPI

Initialize the metadata export service
private void initMetadataServiceExports(a) {
    this.metadataServiceExporters = getExtensionLoader(MetadataServiceExporter.class).getSupportedExtensionInstances();
}
Copy the code

Get a list of MetadataServiceExporter through Dubbo SPI

Initialize the event listener
private void initEventListener(a) {
    // Add the current instance to the listener
    addEventListener(this);
}
​
public DubboBootstrap addEventListener(EventListener
        listener) {
        eventDispatcher.addEventListener(listener);
        return this;
    }
Copy the code

Adds the current instance to the listener

Export services

private void exportServices(a) {
    configManager.getServices().forEach(sc -> {
        // TODO, compatible with ServiceConfig.export()
        ServiceConfig serviceConfig = (ServiceConfig) sc;
        serviceConfig.setBootstrap(this);
​
        // Asynchronous export
        if(exportAsync) { ExecutorService executor = executorRepository.getServiceExporterExecutor(); Future<? > future = executor.submit(() -> { sc.export(); exportedServices.add(sc); }); asyncExportingFutures.add(future);// Synchronize export
        } else {
            / / exportsc.export(); exportedServices.add(sc); }}); }Copy the code

To export dubbo Service, determine whether to export the service synchronously or asynchronously.

Export the metadata service

private void exportMetadataService(a) {
    metadataServiceExporters
            .stream()
            .filter(this::supports)
            .forEach(MetadataServiceExporter::export);
}
Copy the code

Register service instances

private void registerServiceInstance(a) {
    if (CollectionUtils.isEmpty(getServiceDiscoveries())) {
        return;
    }
    / / get ApplicationConfig
    ApplicationConfig application = getApplication();

    // Get the application name
    String serviceName = application.getName();

    // Get the URL of the metadata service export
    URL exportedURL = selectMetadataServiceExportedURL();
    / / for the host
    String host = exportedURL.getHost();
    / / get the port
    int port = exportedURL.getPort();
    // Instantiate ServiceInstance
    ServiceInstance serviceInstance = createServiceInstance(serviceName, host, port);
    // Prepare to register ServiceInstance
    preRegisterServiceInstance(serviceInstance);
    // Get the discovered Service and register it with ServiceInstance
    getServiceDiscoveries().forEach(serviceDiscovery -> serviceDiscovery.register(serviceInstance));
}
Copy the code

Reference service

private void referServices(a) {
    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); }}}); }Copy the code

conclusion

The above is Dubbo service after the start of the load process, just a simple comb, we have talked about before, will be in the subsequent source analysis, for each stage of detailed explanation.