Spring 原始碼解析十五:SpringCloud 的基礎元件

senntyou發表於2021-12-01

Spring 原始碼解析十五:SpringCloud 的基礎元件

SpringCloud 並不是只有一個專案,而是很多專案構成的生態體系總稱,如

但這些專案都依賴一個基礎專案 spring-cloud-commons

spring-cloud-commons 主要有 3 個模組

  • spring-cloud-context:構建一個 Bootstrap 容器,並讓其成為原有的 SpringBoot 程式構建的容器的父容器,所以使用 SpringCloud 的方式與 SpringBoot 是差不多的
  • spring-cloud-commons:對微服務中的服務註冊與發現、負載均衡、熔斷器等功能提供一個抽象層程式碼,這個抽象層與具體的實現無關,這些功能可以採用不同的技術去實現
  • spring-cloud-loadbalancer:一個客戶端負載均衡器,類似於 Ribbon,用於替換 Ribbon(Ribbon 已經進入維護模式)

1. spring-cloud-context

元件的載入仍然是通過 Spring Factories 擴充套件載入機制載入的,定在 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

下面主要解析一下 BootstrapApplicationListenerPropertySourceBootstrapConfiguration

1.1. BootstrapApplicationListener

BootstrapApplicationListener
的主要功能是擴充套件配置檔案的載入位置、新增 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
的主要功能是針對 SpringCloud 的日誌、Profile、配置處理

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

這個註解是 spring-cloud-context 主要的註解,用於初始化 Spring Cloud 元件

BootstrapConfiguration

// 通過前面介紹的 `BootstrapImportSelector` 來實現自動載入在 `spring.factories` 中使用
// `org.springframework.cloud.bootstrap.BootstrapConfiguration` 配置的類
public @interface BootstrapConfiguration {}

2. spring-cloud-commons

元件的載入仍然是通過 Spring Factories 擴充套件載入機制載入的,定在 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

這兩個註解是 spring-cloud-commons 主要的註解,@EnableDiscoveryClient 用於新增服務發現客戶端,@LoadBalanced 用於標誌請求是負載均衡的

EnableDiscoveryClient

// 自動例項化 `EnableDiscoveryClientImportSelector`,並載入Spring IOC容器
// 例項化 `@EnableDiscoveryClient` 註解的類,但不做實際註冊、發現處理
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {}

LoadBalanced

// 沒有任何處理,只是定義註解
public @interface LoadBalanced {}

@EnableDiscoveryClient@LoadBalanced 都沒有實質上的處理,只是定義好註解規範,留待其他元件實現

3. spring-cloud-loadbalancer

元件的載入仍然是通過 Spring Factories 擴充套件載入機制載入的,定在 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

這裡主要解析一下 LoadBalancerAutoConfiguration

3.1. LoadBalancerAutoConfiguration

LoadBalancerAutoConfiguration
的主要功能是完成 spring.cloud.loadbalancer 的自動配置裝配,並例項化負載均衡元件

// 繼承 `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 {
    // ... 程式碼省略
}

因為 LoadBalancerAutoConfiguration 繼承了 LoadBalancerClients
的註解,所以來看看 LoadBalancerClients

// 自動例項化 `LoadBalancerClientConfigurationRegistrar`,並載入Spring IOC容器
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients {
    // ... 程式碼省略
}

再來看看 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

這兩個註解是 spring-cloud-loadbalancer 主要的註解,用於新增負載均衡客戶端

LoadBalancerClients

// 自動例項化 `LoadBalancerClientConfigurationRegistrar`,並載入Spring IOC容器
// 自動處理標記有 `@LoadBalancerClients` & `@LoadBalancerClient` 註解的類
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients {
    // ... 程式碼省略
}

LoadBalancerClient

// 自動例項化 `LoadBalancerClientConfigurationRegistrar`,並載入Spring IOC容器
// 自動處理標記有 `@LoadBalancerClients` & `@LoadBalancerClient` 註解的類
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClient {
    // ... 程式碼省略
}

後續

更多部落格,檢視 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版權宣告:自由轉載-非商用-非衍生-保持署名(創意共享 3.0 許可證

相關文章