2

Spring source code analysis 15: the basic components of SpringCloud

SpringCloud not just one project, but the general term for the ecosystem composed of many projects, such as

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

spring-cloud-commons mainly has 3 modules

  • spring-cloud-context : Build a Bootstrap container and make it the parent container of the container built by the original SpringBoot program, so the way to use SpringCloud is similar to SpringBoot
  • spring-cloud-commons : Provides an abstraction layer code for service registration and discovery, load balancing, fuse and other functions in microservices. This abstraction layer has nothing to do with 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 loading of components is still loaded through the Spring Factories extension loading mechanism, which is set at spring.factories

# 属性自动装配
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

# 应用监听器
org.springframework.context.ApplicationListener=\
org.springframework.cloud.bootstrap.BootstrapApplicationListener,\
org.springframework.cloud.bootstrap.LoggingSystemShutdownListener,\
org.springframework.cloud.context.restart.RestartListener

# Spring Cloud 初始化组件
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 初始化注册
org.springframework.boot.BootstrapRegistryInitializer=\
org.springframework.cloud.bootstrap.RefreshBootstrapRegistryInitializer,\
org.springframework.cloud.bootstrap.TextEncryptorConfigBootstrapper

# 环境后置处理
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.bootstrap.encrypt.DecryptEnvironmentPostProcessor,\
org.springframework.cloud.util.random.CachedRandomPropertySourceEnvironmentPostProcessor

The following mainly analyzes BootstrapApplicationListener and PropertySourceBootstrapConfiguration

1.1. BootstrapApplicationListener

BootstrapApplicationListener
The main function of is to extend the loading position 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) {
        // ... 代码省略

        // 初始化上下文环境
        context = bootstrapServiceContext(environment, event.getSpringApplication(), configName);

        // ... 代码省略
    }

    // 初始化上下文环境
    private ConfigurableApplicationContext bootstrapServiceContext(ConfigurableEnvironment environment,
                final SpringApplication application, String configName) {
        // ... 代码省略

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

        // 扩展 spring.cloud.bootstrap.location 配置到 spring.config.location 中
        if (StringUtils.hasText(configLocation)) {
            bootstrapMap.put("spring.config.location", configLocation);
        }
        // 扩展 spring.cloud.bootstrap.additional-location 配置到 spring.config.additional-location 中
        if (StringUtils.hasText(configAdditionalLocation)) {
            bootstrapMap.put("spring.config.additional-location", configAdditionalLocation);
        }

        // ... 代码省略

        // 通过 BootstrapImportSelector 添加 `spring.factories` 的加载组件 `org.springframework.cloud.bootstrap.BootstrapConfiguration`
        builder.sources(BootstrapImportSelectorConfiguration.class);
    }
}
public class BootstrapImportSelector implements EnvironmentAware, DeferredImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // ... 代码省略

        // 通过 SpringFactoriesLoader 加载 `org.springframework.cloud.bootstrap.BootstrapConfiguration` 指定的组件
        List<String> names = new ArrayList<>(
                SpringFactoriesLoader.loadFactoryNames(BootstrapConfiguration.class, classLoader));
        // 配置中的 spring.cloud.bootstrap.sources 也当做 BootstrapConfiguration 组件加载
        names.addAll(Arrays.asList(StringUtils
                .commaDelimitedListToStringArray(this.environment.getProperty("spring.cloud.bootstrap.sources", ""))));

        // ... 代码省略
    }
}

1.2. PropertySourceBootstrapConfiguration

PropertySourceBootstrapConfiguration
The main function of is for SpringCloud log, profile, configuration processing

public class PropertySourceBootstrapConfiguration
        implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // ... 代码省略

        MutablePropertySources propertySources = environment.getPropertySources();

        // ... 代码省略

        // 加载自定义的配置加载处理,spring-cloud-config 的分布式配置功能就有赖于此
        insertPropertySources(propertySources, composite);

        // 处理 logging.config 指定的日志配置
        String logConfig = environment.resolvePlaceholders("${logging.config:}");
        LogFile logFile = LogFile.get(environment);
        reinitializeLoggingSystem(environment, logConfig, logFile);

        // 设置日志记录等级
        setLogLevels(applicationContext, environment);

        // 处理 spring.profiles.active 激活的环境
        handleIncludedProfiles(environment);
    }
}

1.3. @BootstrapConfiguration

This annotation is the spring-cloud-context , used to initialize Spring Cloud components

BootstrapConfiguration

// 通过前面介绍的 `BootstrapImportSelector` 来实现自动加载在 `spring.factories` 中使用
// `org.springframework.cloud.bootstrap.BootstrapConfiguration` 配置的类
public @interface BootstrapConfiguration {}

2. spring-cloud-commons

The loading of components is still loaded through the Spring Factories extension loading mechanism, which is set at spring.factories

# 属性自动装配
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

# 环境后置处理
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.client.HostInfoEnvironmentPostProcessor

# 错误分析
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.cloud.configuration.CompatibilityNotMetFailureAnalyzer

2.1. @EnableDiscoveryClient & @LoadBalanced

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

EnableDiscoveryClient

// 自动实例化 `EnableDiscoveryClientImportSelector`,并载入Spring IOC容器
// 实例化 `@EnableDiscoveryClient` 注解的类,但不做实际注册、发现处理
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {}

LoadBalanced

// 没有任何处理,只是定义注解
public @interface LoadBalanced {}

@EnableDiscoveryClient and @LoadBalanced have no substantial processing, just define the annotation specifications, and leave it to other components to implement

3. spring-cloud-loadbalancer

The loading of components is still loaded through the Spring Factories extension loading mechanism, which is set at spring.factories

# 属性自动装配
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

The main analysis here is LoadBalancerAutoConfiguration

3.1. LoadBalancerAutoConfiguration

LoadBalancerAutoConfiguration
The main function is to complete spring.cloud.loadbalancer , and instantiate the load balancing component

// 继承 `LoadBalancerClients` 的注解
@LoadBalancerClients
// 自动装配 `spring.cloud.loadbalancer` 配置
@EnableConfigurationProperties(LoadBalancerProperties.class)
// 使用 `spring.cloud.loadbalancer.enabled` 来启动此组件
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.enabled", havingValue = "true", matchIfMissing = true)
public class LoadBalancerAutoConfiguration {
    // ... 代码省略
}

Because LoadBalancerAutoConfiguration inherits LoadBalancerClients
Comment, so take a look at LoadBalancerClients

// 自动实例化 `LoadBalancerClientConfigurationRegistrar`,并载入Spring IOC容器
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients {
    // ... 代码省略
}

Let's take a look at LoadBalancerClientConfigurationRegistrar

public class LoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        // 获取 @LoadBalancerClients 注解
        Map<String, Object> attrs = metadata.getAnnotationAttributes(LoadBalancerClients.class.getName(), true);
        if (attrs != null && attrs.containsKey("value")) {
            // 获取注解中 value 指定的值,并注册bean组件定义
            AnnotationAttributes[] clients = (AnnotationAttributes[]) attrs.get("value");
            for (AnnotationAttributes client : clients) {
                registerClientConfiguration(registry, getClientName(client), client.get("configuration"));
            }
        }

        // ... 代码省略

        // 获取 @LoadBalancerClient 注解
        Map<String, Object> client = metadata.getAnnotationAttributes(LoadBalancerClient.class.getName(), true);
        // 获取注解中 name/value 指定的值,并注册bean组件定义
        String name = getClientName(client);
        if (name != null) {
            registerClientConfiguration(registry, name, client.get("configuration"));
        }
    }
}

3.2. @LoadBalancerClients & @LoadBalancerClient

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

LoadBalancerClients

// 自动实例化 `LoadBalancerClientConfigurationRegistrar`,并载入Spring IOC容器
// 自动处理标记有 `@LoadBalancerClients` & `@LoadBalancerClient` 注解的类
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients {
    // ... 代码省略
}

LoadBalancerClient

// 自动实例化 `LoadBalancerClientConfigurationRegistrar`,并载入Spring IOC容器
// 自动处理标记有 `@LoadBalancerClients` & `@LoadBalancerClient` 注解的类
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClient {
    // ... 代码省略
}

Follow-up

For more blogs, check out https://github.com/senntyou/blogs

Author: Shen Yuzhi (@senntyou)

Copyright notice: Freely reproduced-non-commercial-non-derivative-keep the signature ( Creative Commons 3.0 License )


深雨
12.7k 声望6.5k 粉丝

达则兼济天下,穷则独善其身。