Spring 源码解析十五:SpringCloud 的基础组件

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 许可证

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

12.7k 声望
6.5k 粉丝
0 条评论
推荐阅读
从零搭建 Node.js 企业级 Web 服务器(零):静态服务
过去 5 年,我前后在菜鸟网络和蚂蚁金服做开发工作,一方面支撑业务团队开发各类业务系统,另一方面在自己的技术团队做基础技术建设。期间借着 Node.js 的锋芒做了不少 Web 系统,有的至今生气蓬勃、有的早已夭折...

乌柏木172阅读 13.8k评论 10

Spring事务传播行为详解
Spring在TransactionDefinition接口中规定了7种类型的事务传播行为。事务传播行为是Spring框架独有的事务增强特性,他不属于的事务实际提供方数据库行为。这是Spring为我们提供的强大的工具箱,使用事务传播行可...

JerryTse242阅读 122.7k评论 97

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木75阅读 7k评论 16

从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木45阅读 8.5k评论 6

从零搭建 Node.js 企业级 Web 服务器(二):校验
校验就是对输入条件的约束,避免无效的输入引起异常。Web 系统的用户输入主要为编辑与提交各类表单,一方面校验要做在编辑表单字段与提交的时候,另一方面接收表单的接口也要做足校验行为,通过前后端共同控制输...

乌柏木35阅读 6.6k评论 10

从零搭建 Node.js 企业级 Web 服务器(五):数据库访问
回顾 从零搭建 Node.js 企业级 Web 服务器(一):接口与分层,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,控制层与服务层实现了业务处理过程,模型层定义了业务实体并以 对象-关系...

乌柏木34阅读 5k评论 9

一文搞懂秒杀系统,欢迎参与开源,提交PR,提高竞争力。早日上岸,升职加薪。
前言秒杀和高并发是面试的高频考点,也是我们做电商项目必知必会的场景。欢迎大家参与我们的开源项目,提交PR,提高竞争力。早日上岸,升职加薪。知识点详解秒杀系统架构图秒杀流程图秒杀系统设计这篇文章一万多...

王中阳Go32阅读 2.4k评论 1

封面图

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

12.7k 声望
6.5k 粉丝
宣传栏