文章目录
前言
本篇主要介绍客户端主动向服务端发起请求拉取配置信息,以及加载配置文件的核心源码。
一、NacosPropertySourceLocator
前篇中提到,在Nacos客户端启动的过程中,会通过Spring Boot的自动配置机制,加载NacosConfigBootstrapConfiguration
,该类中会条件装配三个Bean,第一个是和配置文件的信息有关,第二个是和接收listenExecutebell
队列中的标记并向服务端发起请求,获取配置信息有关。第三个则是和加载配置文件,以及获取配置信息有关。
客户端Spring Boot启动的过程中,会去调用其中的locate
方法,在该方法中,主要做了四件事:
- 获取配置中心服务
- 加载共享的配置文件
- 加载扩展的配置文件
- 加载当前应用配置
1.1、加载共享的配置文件
共享的配置文件,对应的是bootstrap.yml
的shared-configs
这一部分:
NacosConfigProperties
也是在NacosConfigBootstrapConfiguration
中加入的Bean,代表了Nacos的配置信息。
1.2、加载扩展的配置文件
扩展的配置文件,对应的是bootstrap.yml
的extension-configs
这一部分:
1.3、加载当前应用配置
按照 服务名、服务名.后缀名、服务名-环境名.后缀名 的顺序加载,后者的优先级高于前者
无论是上述的何种方式,最后都会调用到loadNacosDataIfPresent
方法:
然后调用NacosPropertySourceBuilder
的build
方法:
调用loadNacosData
:
loadNacosData
的核心代码是configService.getConfig
:
最终调用到的是getConfigInner
,其中优先会去读取本地磁盘上保存的配置。
如果获取不到,则会发起请求,从服务端获取配置:
后面的逻辑就和前篇中提到的,客户端接收到listenExecutebell
队列中的标记,然后发起请求从服务端获取存在服务端磁盘上的配置,然后获取到结果,存在客户端磁盘上完全相同了
二、补充:bootstrap.yml 与 application.yml 的优先级问题
首先,在原生的Spring Boot 中 是不存在bootstrap.yml 这个概念的。它的出现是由于 Spring Cloud 引入的一层机制,Spring Boot 原生启动时,配置加载顺序由ConfigFileApplicationListener
控制,加载如下配置文件(优先级从高到低):
加载顺序 | 配置文件来源 | 描述 |
---|---|---|
1 | 命令行参数 | 如 --server.port=8081 |
2 | application.properties / application.yml (位于 config/ 目录) | 外部配置优先 |
3 | application.properties / application.yml (位于 classpath 根目录) | 通常用于默认配置 |
4 | 默认属性(由代码指定) | SpringApplication.setDefaultProperties(...) |
bootstrap.yml
是 Spring Cloud 中通过扩展机制添加的,在spring-cloud-alibaba
的相关组件的spring-cloud-context
的jar包中的spring.factories
文件中,引入了BootstrapApplicationListener
监听器。
spring-cloud-context
是个特殊的 Bootstrap Context,由BootstrapApplicationListener
在应用启动最早阶段注入。其作用是优先加载一批基础配置(如 Nacos、Apollo、Consul)来初始化上下文环境,供后续正式环境使用。
该监听器监听了Spring Boot启动过程中发布的ApplicationEnvironmentPreparedEvent
事件。
触发时机:
它会在主 ApplicationContext 之前:
- 创建一个“父上下文”(BootstrapContext)
- 加载 bootstrap.yml
- 提前注入环境变量到 Environment
- 然后再加载 application.yml 到主 ApplicationContext
在其onApplicationEvent
方法中:
如果开发者明确配置了 spring.cloud.bootstrap.enabled=false,则直接跳过,不加载 bootstrap.yml。
如果 bootstrap 的配置已经加载进了环境变量中(如:bootstrapProperties),就不用重复初始化。
是否已有这个“父上下文”被创建过
如果没有,则创建 Bootstrap 上下文,将 context 加入到主上下文之前,作为其 parent
这个步骤将 bootstrap 加载的配置文件内容注入到当前的 Environment 中。虽然顺序上早于 application.yml,但其优先级较低,这就是为什么 application.yml 可以覆盖 bootstrap.yml 中的值。