>>>> 😜😜😜 Github: 👉 github.com/black-ant CASE Backup: 👉 gitee.com/antblack/ca…

A. The preface

This article will only preview the main process of Bootstrap initialization. Some details will be analyzed separately

Dubbo 3.0 uses the DubboBootstrap initialization logic. DubboBootstrap startup logic is as follows:

// The core principle is the ApplicationContextEvent event. When the SpringApplication is started, the event will be publishedC- AbstractApplicationContext # refresh : C - release ApplicationContextEvent events DubboBootstrapApplicationListener # onApplicationContextEvent: To monitor Application event C - DubboBootstrapApplicationListener # # onContextRefreshedEvent C - DubboBootstrap start: start load operationCopy the code

Mainly concerned with classes

// Reference class:
DubboBeanUtils
ServiceAnnotationPostProcessor
DubboClassPathBeanDefinitionScanner
    
    
// Listener:
DubboBootstrapApplicationListener    
Copy the code

2. Detailed explanation of entrance

Dubbo is initialized by the following classes: DubboBootstrap –

// Step 1 : DubboBootstrapApplicationListener
public void onApplicationContextEvent(ApplicationContextEvent event) {
	if (DubboBootstrapStartStopListenerSpringAdapter.applicationContext == null) {
		DubboBootstrapStartStopListenerSpringAdapter.applicationContext = event.getApplicationContext();
	}
        // Initialize Bootstrap after the container is started
	if (event instanceof ContextRefreshedEvent) {
		onContextRefreshedEvent((ContextRefreshedEvent) event);
        // The container closes the logic
	} else if (event instanceofContextClosedEvent) { onContextClosedEvent((ContextClosedEvent) event); }}// Step 2-1 
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
	if(dubboBootstrap.getTakeoverMode() == BootstrapTakeoverMode.SPRING) { dubboBootstrap.start(); }}// Step 2-2 
private void onContextClosedEvent(ContextClosedEvent event) {
	if(dubboBootstrap.getTakeoverMode() == BootstrapTakeoverMode.SPRING) { DubboShutdownHook.getDubboShutdownHook().run(); }}Copy the code

DubboBootstrap Startup process

3.1 Start Main process

The start link mainly consists of the following links:

Step 1: Sets the boot parameter Step2: initialize Initializes Step3: exportServices Outputs the Services Step4ReferServices Registers referService Step5: onStart() starts (asynchronously after Thread is created)// Start Dubbo container environment
dubboBootstrap.start(); 

// Step 1: Start logic
public DubboBootstrap start(a) {
    if (started.compareAndSet(false.true)) {
        startup.set(false);
        initialized.set(false);
        shutdown.set(false);
        awaited.set(false);

        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();
        if (asyncExportingFutures.size() > 0 || asyncReferringFutures.size() > 0) {
            new Thread(() -> {
                try {
                    this.awaitFinish();
                } catch (Exception e) {
                    logger.warn(NAME + " asynchronous export / refer occurred an exception.");
                }
                startup.set(true);
                onStart();
            }).start();
        } else {
            startup.set(true); onStart(); }}return this;
}
Copy the code

3.2 Setting Startup Parameters

if (started.compareAndSet(false.true)) 
    
startup.set(false);
initialized.set(false);
shutdown.set(false);
awaited.set(false);
    
// There are several main operations:
1.Atomic Settings have been enabled2.Set properties// Let's focus on the four attributes
private AtomicBoolean initialized = new AtomicBoolean(false);
private AtomicBoolean started = new AtomicBoolean(false);
private AtomicBoolean startup = new AtomicBoolean(true);
private AtomicBoolean destroyed = new AtomicBoolean(false);
private AtomicBoolean shutdown = new AtomicBoolean(false) 
    

Copy the code

3.3 Initialize Initializes the content

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

    ApplicationModel.initFrameworkExts();

    // Initialize the configuration
    startConfigCenter();
    loadConfigsFromProps();
    checkGlobalConfigs();

    // Initialize the Service
    startMetadataCenter();
    initMetadataService();
}
Copy the code

3.3.1 ApplicationModel. InitFrameworkExts ()

// C- DubboBootstrap
public static void initFrameworkExts(a) {
        Set<FrameworkExt> exts = ExtensionLoader.getExtensionLoader(FrameworkExt.class).getSupportedExtensionInstances();
    	// PIC21005
        for(FrameworkExt ext : exts) { ext.initialize(); }}// Step 1: Plug-in processing via SPI
@SPI
public interface FrameworkExt extends Lifecycle {}// Add: Lifecycle object in Dubbo
- ConfigManager
- Environment
- LifecycleAdapter
- ServiceRepository
- SpringExtensionFactory


// Step 2-1: ConfigManager section
public void initialize(a) throws IllegalStateException {
        String configModeStr = null;
        try {
            configModeStr = (String) ApplicationModel.getEnvironment().getConfiguration().getProperty(DUBBO_CONFIG_MODE);
            if (StringUtils.hasText(configModeStr)) {
                this.configMode = ConfigMode.valueOf(configModeStr.toUpperCase()); }}catch (Exception e) {
            throw newIllegalArgumentException(msg, e); }}// Step 2-2: Environment
public void initialize(a) throws IllegalStateException {
        if (initialized.compareAndSet(false.true)) {
            this.propertiesConfiguration = new PropertiesConfiguration();
            this.systemConfiguration = new SystemConfiguration();
            this.environmentConfiguration = new EnvironmentConfiguration();
            this.externalConfiguration = new InmemoryConfiguration("ExternalConfig");
            this.appExternalConfiguration = new InmemoryConfiguration("AppExternalConfig");
            this.appConfiguration = new InmemoryConfiguration("AppConfig"); loadMigrationRule(); }}// Step 2-3: ServiceRepository
Copy the code

PIC21005: FrameworkExt List of objects

3.3.2 rainfall distribution on 10-12 startConfigCenter briefly

This stage can be divided into 3 steps:

  1. Load ApplicationConfig and ConfigCenterConfig respectively
  2. Configure configCenterConfig
  3. Final refresh of Application, Monitor, Modules, and other components
private void startConfigCenter(a) {

    // Step 1: Process the corresponding Config, which can be divided into two types simply
    
    Type 1: a class configuration exists
    // 1. Instantiate a class object of the corresponding class type using newInstance
    // 2. Call the corresponding refush for the refresh process (TODO: subsequent analysis, that is, the configuration rewrite process)
    // 3. Cache to configManager
    
    // > Type 2: No corresponding configuration exists
    // 1. Fetch Environment directly from ApplicationModel
    // 2. Instantiate newInstance to configManager
    loadConfigs(ApplicationConfig.class);
    loadConfigs(ConfigCenterConfig.class);
 
 
    useRegistryAsConfigCenterIfNecessary();

    // check Config Center -> PS:332001
    Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();
    if (CollectionUtils.isEmpty(configCenters)) {
        // The registry is usually configured with a value here. If it is empty, the base implementation is new here
    } else {
        for (ConfigCenterConfig configCenterConfig : configCenters) {
            // Step 2: Configure configCenterConfigconfigCenterConfig.refresh(); ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig); }}if (CollectionUtils.isNotEmpty(configCenters)) {
        CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();
        
        // Configure the environment link
        for (ConfigCenterConfig configCenter : configCenters) {
            // Pass config from ConfigCenterBean to environment
            environment.updateExternalConfigMap(configCenter.getExternalConfiguration());
            environment.updateAppExternalConfigMap(configCenter.getAppExternalConfiguration());

            // Fetch config from remote config center
            compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));
        }
        environment.setDynamicConfiguration(compositeDynamicConfiguration);
    }
    
    // Step 3: Refresh TODO for Application, Monitor, Modules and other components
    configManager.refreshAll();
}
Copy the code

Added: the ConfigCenterConfig object’s role

This object contains basic connection configuration information, such as Protocol, Address, port, Cluster, and namespace

The ConfigCenterConfig object can be used flexibly to integrate many different registries

Supplementary: PS:332001 structure

3.3.3 loadConfigsFromProps briefly

Similar to the above, loadConfigs reads the configuration file with a special prefix

I have seen several open source projects loading configuration files, which basically lead to the same path. They are distinguished by classes and loaded by prefixes, which will be analyzed separately later

private void loadConfigsFromProps(a) {

    // application config has load before starting config center
    // load dubbo.applications.xxx
    loadConfigs(ApplicationConfig.class);

    // load dubbo.modules.xxx
    loadConfigs(ModuleConfig.class);

    // load dubbo.monitors.xxx
    loadConfigs(MonitorConfig.class);

    // load dubbo.metricses.xxx
    loadConfigs(MetricsConfig.class);

    // load multiple config types:
    // load dubbo.protocols.xxx
    loadConfigs(ProtocolConfig.class);

    // load dubbo.registries.xxx
    loadConfigs(RegistryConfig.class);

    // load dubbo.providers.xxx
    loadConfigs(ProviderConfig.class);

    // load dubbo.consumers.xxx
    loadConfigs(ConsumerConfig.class);

    // load dubbo.metadata-report.xxx
    loadConfigs(MetadataReportConfig.class);

    // config centers has bean loaded before starting config center
    //loadConfigs(ConfigCenterConfig.class);

}
Copy the code

3.3.4 checkGlobalConfigs briefly

ConfigValidationUtils is used for configuration verification, port handling, and finally refresh

private void checkGlobalConfigs(a) {
    // check config types (ignore metadata-center)
    List<Class<? extends AbstractConfig>> multipleConfigTypes = Arrays.asList(
        ApplicationConfig.class,
        ProtocolConfig.class,
        RegistryConfig.class,
        MetadataReportConfig.class,
        ProviderConfig.class,
        ConsumerConfig.class,
        MonitorConfig.class,
        ModuleConfig.class,
        MetricsConfig.class,
        SslConfig.class);

    for (Class<? extends AbstractConfig> configType : multipleConfigTypes) {
        // Verify the configuration with ConfigValidationUtils
        checkDefaultAndValidateConfigs(configType);
    }

    // check port conflicts
    // 
    Map<Integer, ProtocolConfig> protocolPortMap = new LinkedHashMap<>();
    for (ProtocolConfig protocol : configManager.getProtocols()) {
        Integer port = protocol.getPort();
        if (port == null || port == -1) {
            continue;
        }
        
        // If there is a port conflict, an exception will be thrown
        ProtocolConfig prevProtocol = protocolPortMap.get(port);
        if(prevProtocol ! =null) {
            throw new IllegalStateException
        }
        protocolPortMap.put(port, protocol);
    }

    // check reference and service
    // TODO: TODO: TODO: TODO: TODO: TODO: TODO
    for(ReferenceConfigBase<? > reference : configManager.getReferences()) { reference.refresh(); }for(ServiceConfigBase service : configManager.getServices()) { service.refresh(); }}Copy the code

3.3.5 startMetadataCenter briefly

Metadata is a new feature. You can set MetadataReportConfig with the prefix dubo.metadata-report in the configuration file

What is metadata:

  • Metadata is to relieve the pressure on the registry by putting some of the content stored in the registry into the metadata center.
  • Data in the metadata center is for personal use only
  • No listening or notification is required, greatly reducing performance consumption
private void startMetadataCenter(a) {

    useRegistryAsMetadataCenterIfNecessary();

    ApplicationConfig applicationConfig = getApplication();

    String metadataType = applicationConfig.getMetadataType();
    // FIXME, multiple metadata config support.
    Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();
    if (CollectionUtils.isEmpty(metadataReportConfigs)) {
        / /... The remote registry is configured with data by default, and no exceptions are thrown
    }

    for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) {
        / / < dubbo: metadata - report address = "zookeeper: / / 127.0.0.1:2181" id = "metadata - the center - zookeeper - 2181" / >
        ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);
        if(! metadataReportConfig.isValid()) {continue;
        }
        
        // Instantiate by instanceMetadataReportInstance.init(metadataReportConfig); }}Copy the code

3.3.6 initMetadataService briefly

    private void initMetadataService(a) {
// startMetadataCenter();
        this.metadataService = getDefaultExtension();
        this.metadataServiceExporter = new ConfigurableMetadataServiceExporter(metadataService);
    }
Copy the code

3.4 exportServices

See service registration system for details

3.5 referServices

See service discovery System for details

3.6 onStart calls listener extension

private void onStart(a) {
	ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
	exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));
}

Copy the code

conclusion

This chapter is mainly to summarize and have a preliminary understanding of all the concepts, and then gradually improve the details of the whole process, as well as the learning and use of its code