Spring source code analysis XV: basic components of spring cloud

Posted by pmeasham on Tue, 30 Nov 2021 09:05:49 +0100

Spring source code analysis XV: basic components of spring cloud

Spring cloud does not have only one project, but the general name of the ecosystem composed of many projects, such as

But these projects all rely on one basic project spring-cloud-commons

Spring cloud commons mainly has three modules

  • Spring cloud context: build a Bootstrap container and make it the parent container of the container built by the original spring boot program, so the way to use spring cloud is similar to that of spring boot
  • Spring cloud Commons: it provides an abstract layer code for service registration and discovery, load balancing, fuse and other functions in microservices. This abstract layer is independent of the specific implementation. These functions can be implemented by different technologies
  • Spring cloud loadbalancer: a client load balancer, similar to Ribbon, used to replace Ribbon (Ribbon has entered maintenance mode)

1. spring-cloud-context

The component is still loaded through the Spring Factories extended loading mechanism, which is set at spring.factories

# Attribute auto assembly
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\
org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration,\
org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,\
org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration,\
org.springframework.cloud.autoconfigure.WritableEnvironmentEndpointAutoConfiguration

# Application listener
org.springframework.context.ApplicationListener=\
org.springframework.cloud.bootstrap.BootstrapApplicationListener,\
org.springframework.cloud.bootstrap.LoggingSystemShutdownListener,\
org.springframework.cloud.context.restart.RestartListener

# Spring Cloud initialization component
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration,\
org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration,\
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration

# Spring Boot initialization registration
org.springframework.boot.BootstrapRegistryInitializer=\
org.springframework.cloud.bootstrap.RefreshBootstrapRegistryInitializer,\
org.springframework.cloud.bootstrap.TextEncryptorConfigBootstrapper

# Environmental post-processing
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.bootstrap.encrypt.DecryptEnvironmentPostProcessor,\
org.springframework.cloud.util.random.CachedRandomPropertySourceEnvironmentPostProcessor

The following mainly analyzes the bootstrap applicationlistener and propertysourcebootstrap configuration

1.1. BootstrapApplicationListener

BootstrapApplicationListener
The main function of is to extend the loading location of the configuration file and add the loading component of spring.factories

public class BootstrapApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        // ... code omitted

        // Initialize context
        context = bootstrapServiceContext(environment, event.getSpringApplication(), configName);

        // ... code omitted
    }

    // Initialize context
    private ConfigurableApplicationContext bootstrapServiceContext(ConfigurableEnvironment environment,
                final SpringApplication application, String configName) {
        // ... code omitted

        String configLocation = environment.resolvePlaceholders("${spring.cloud.bootstrap.location:}");
        String configAdditionalLocation = environment
                .resolvePlaceholders("${spring.cloud.bootstrap.additional-location:}");
        Map<String, Object> bootstrapMap = new HashMap<>();

        // Extend spring.cloud.bootstrap.location configuration to spring.config.location
        if (StringUtils.hasText(configLocation)) {
            bootstrapMap.put("spring.config.location", configLocation);
        }
        // Extend the spring.cloud.bootstrap.additional-location configuration to spring.config.additional-location
        if (StringUtils.hasText(configAdditionalLocation)) {
            bootstrapMap.put("spring.config.additional-location", configAdditionalLocation);
        }

        // ... code omitted

        // Add the loading component 'org.springframework.cloud.bootstrap.bootstrappconfiguration' of 'spring.factories' through bootstrappimportselector`
        builder.sources(BootstrapImportSelectorConfiguration.class);
    }
}
public class BootstrapImportSelector implements EnvironmentAware, DeferredImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // ... code omitted

        // Load the components specified by 'org. Springframework. Cloud. Bootstrap. Bootstrap configuration' through SpringFactoriesLoader
        List<String> names = new ArrayList<>(
                SpringFactoriesLoader.loadFactoryNames(BootstrapConfiguration.class, classLoader));
        // spring.cloud.bootstrap.sources in the configuration is also loaded as a bootstrap configuration component
        names.addAll(Arrays.asList(StringUtils
                .commaDelimitedListToStringArray(this.environment.getProperty("spring.cloud.bootstrap.sources", ""))));

        // ... code omitted
    }
}

1.2. PropertySourceBootstrapConfiguration

PropertySourceBootstrapConfiguration
The main functions of are log, Profile and configuration processing for spring cloud

public class PropertySourceBootstrapConfiguration
        implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // ... code omitted

        MutablePropertySources propertySources = environment.getPropertySources();

        // ... code omitted

        // The distributed configuration function of spring cloud config depends on the custom configuration loading process
        insertPropertySources(propertySources, composite);

        // Process the log configuration specified by logging.config
        String logConfig = environment.resolvePlaceholders("${logging.config:}");
        LogFile logFile = LogFile.get(environment);
        reinitializeLoggingSystem(environment, logConfig, logFile);

        // Set logging level
        setLogLevels(applicationContext, environment);

        // Environment that handles spring.profiles.active activation
        handleIncludedProfiles(environment);
    }
}

1.3. @BootstrapConfiguration

This annotation is the main annotation of Spring Cloud context, which is used to initialize Spring Cloud components

BootstrapConfiguration

// Automatic loading is realized through the 'bootstrap importselector' described above. It is used in 'spring.factories'
// `Org. Springframework. Cloud. Bootstrap. Bootstrap configuration ` configured class
public @interface BootstrapConfiguration {}

2. spring-cloud-commons

The component is still loaded through the Spring Factories extended loading mechanism, which is set at spring.factories

# Attribute auto assembly
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.client.CommonsClientAutoConfiguration,\
org.springframework.cloud.client.ReactiveCommonsClientAutoConfiguration,\
org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration,\
org.springframework.cloud.client.discovery.composite.reactive.ReactiveCompositeDiscoveryClientAutoConfiguration,\
org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration,\
org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryClientAutoConfiguration,\
org.springframework.cloud.client.hypermedia.CloudHypermediaAutoConfiguration,\
org.springframework.cloud.client.loadbalancer.AsyncLoadBalancerAutoConfiguration,\
org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration,\
org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration,\
org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration,\
org.springframework.cloud.commons.httpclient.HttpClientConfiguration,\
org.springframework.cloud.commons.util.UtilAutoConfiguration,\
org.springframework.cloud.configuration.CompatibilityVerifierAutoConfiguration,\
org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration,\
org.springframework.cloud.commons.security.ResourceServerTokenRelayAutoConfiguration

# Environmental post-processing
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.client.HostInfoEnvironmentPostProcessor

# error analysis
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.cloud.configuration.CompatibilityNotMetFailureAnalyzer

2.1. @EnableDiscoveryClient & @LoadBalanced

These two annotations are the main annotations of spring cloud commons, @ EnableDiscoveryClient is used to add a service discovery client, and @ LoadBalanced is used to mark that the request is load balanced

EnableDiscoveryClient

// Automatically instantiate 'EnableDiscoveryClientImportSelector' and load it into the Spring IOC container
// Instantiate the class annotated with ` @ EnableDiscoveryClient ', but do not actually register and discover
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {}

LoadBalanced

// There is no processing, just defining annotations
public @interface LoadBalanced {}

@EnableDiscoveryClient and @ LoadBalanced have no substantive processing. They just define the annotation specification and leave it to other components to implement

3. spring-cloud-loadbalancer

The component is still loaded through the Spring Factories extended loading mechanism, which is set at spring.factories

# Attribute auto assembly
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration,\
org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.loadbalancer.config.LoadBalancerCacheAutoConfiguration,\
org.springframework.cloud.loadbalancer.security.OAuth2LoadBalancerClientAutoConfiguration,\
org.springframework.cloud.loadbalancer.config.LoadBalancerStatsAutoConfiguration

Here we mainly analyze loadbalancenautoconfiguration

3.1. LoadBalancerAutoConfiguration

LoadBalancerAutoConfiguration
The main function of spring.cloud.loadbalancer is to complete the automatic configuration and assembly of spring.cloud.loadbalancer and instantiate the load balancing component

// Inherit the annotation of 'LoadBalancerClients'
@LoadBalancerClients
// Auto assemble 'spring.cloud.loadbalancer' configuration
@EnableConfigurationProperties(LoadBalancerProperties.class)
// Use 'spring.cloud.loadbalancer.enabled' to start this component
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.enabled", havingValue = "true", matchIfMissing = true)
public class LoadBalancerAutoConfiguration {
    // ... code omitted
}

Because loadbalancenautoconfiguration inherits LoadBalancerClients
So take a look at LoadBalancerClients

// Automatically instantiate 'LoadBalancerClientConfigurationRegistrar' and load it into the Spring IOC container
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients {
    // ... code omitted
}

Let's see LoadBalancerClientConfigurationRegistrar

public class LoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        // Get @ LoadBalancerClients annotation
        Map<String, Object> attrs = metadata.getAnnotationAttributes(LoadBalancerClients.class.getName(), true);
        if (attrs != null && attrs.containsKey("value")) {
            // Get the value specified by value in the annotation and register the bean component definition
            AnnotationAttributes[] clients = (AnnotationAttributes[]) attrs.get("value");
            for (AnnotationAttributes client : clients) {
                registerClientConfiguration(registry, getClientName(client), client.get("configuration"));
            }
        }

        // ... code omitted

        // Get @ LoadBalancerClient annotation
        Map<String, Object> client = metadata.getAnnotationAttributes(LoadBalancerClient.class.getName(), true);
        // Get the value specified by name/value in the annotation and register the bean component definition
        String name = getClientName(client);
        if (name != null) {
            registerClientConfiguration(registry, name, client.get("configuration"));
        }
    }
}

3.2. @LoadBalancerClients & @LoadBalancerClient

These two annotations are the main annotations of spring cloud loadbalancer, which are used to add load balancing clients

LoadBalancerClients

// Automatically instantiate 'LoadBalancerClientConfigurationRegistrar' and load it into the Spring IOC container
// Automatically process classes marked with ` @ loadbalancerclients ` & ` @ loadbalancerclient ` annotations
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients {
    // ... code omitted
}

LoadBalancerClient

// Automatically instantiate 'LoadBalancerClientConfigurationRegistrar' and load it into the Spring IOC container
// Automatically process classes marked with ` @ loadbalancerclients ` & ` @ loadbalancerclient ` annotations
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClient {
    // ... code omitted
}

follow-up

More blogs, see https://github.com/senntyou/blogs

Author: Deep (@ senntyou)

Copyright notice: free reproduction - non commercial - non derivative - keep signature( Creative sharing 3.0 License)

Topics: Java Spring Back-end