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.