Spring 源码解析十三:SpringBoot 初始化应用时加载的组件
这些组件定义在 spring.factories
中
# 日志系统
org.springframework.boot.logging.LoggingSystemFactory=\
org.springframework.boot.logging.logback.LogbackLoggingSystem.Factory,\
org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.Factory,\
org.springframework.boot.logging.java.JavaLoggingSystem.Factory
# 属性来源加载器
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
# 配置数据来源解析器
org.springframework.boot.context.config.ConfigDataLocationResolver=\
org.springframework.boot.context.config.ConfigTreeConfigDataLocationResolver,\
org.springframework.boot.context.config.StandardConfigDataLocationResolver
# 配置数据加载器
org.springframework.boot.context.config.ConfigDataLoader=\
org.springframework.boot.context.config.ConfigTreeConfigDataLoader,\
org.springframework.boot.context.config.StandardConfigDataLoader
# 应用运行监听器
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# 错误报告器
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers
# 应用上下文初始加载器
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
# 应用监听器
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
# 环境后置处理器
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor,\
org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
# 失败分析器
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.context.config.ConfigDataNotFoundFailureAnalyzer,\
org.springframework.boot.context.properties.IncompatibleConfigurationFailureAnalyzer,\
org.springframework.boot.context.properties.NotConstructorBoundInjectionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PatternParseFailureAnalyzer,\
org.springframework.boot.liquibase.LiquibaseChangelogMissingFailureAnalyzer
# 失败分析报告器
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
1. 日志系统
org.springframework.boot.logging.LoggingSystemFactory=\
org.springframework.boot.logging.logback.LogbackLoggingSystem.Factory,\
org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.Factory,\
org.springframework.boot.logging.java.JavaLoggingSystem.Factory
配置中说明 SpringBoot 内置支持 logback
、logback
、java
原生三种日志处理,具体源代码可以自行探索
2. 属性来源加载器
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
配置中说明 SpringBoot 内置支持 application*.properties
、application*.yaml
两种文件格式加载属性配置来源,具体源代码可以自行探索
3. 配置数据来源解析器 & 配置数据加载器
# 配置数据来源解析器
org.springframework.boot.context.config.ConfigDataLocationResolver=\
org.springframework.boot.context.config.ConfigTreeConfigDataLocationResolver,\
org.springframework.boot.context.config.StandardConfigDataLocationResolver
# 配置数据加载器
org.springframework.boot.context.config.ConfigDataLoader=\
org.springframework.boot.context.config.ConfigTreeConfigDataLoader,\
org.springframework.boot.context.config.StandardConfigDataLoader
这一组放在一起解析,是因为他们一起完成了一个功能:
- ConfigDataLocationResolver
将spring.config.import
、spring.config.addtional-location
、spring.config.location
等资源定位路径下的application*.[properties/yaml]
资源解析成 ConfigDataResource
资源对象,等待加载 - ConfigDataLoader
将解析好的资源对象进行加载,把ConfigDataResource
转换成 ConfigData
(ConfigData
是一组PropertySource
) - 将加载好的
ConfigData
添加到上下文对象中
ConfigTreeConfigDataLocationResolver
与 ConfigTreeConfigDataLoader
主要是读取 Kubernetes Volume 的 configMap 配置,这里就不做解析了
3.1. StandardConfigDataLocationResolver
StandardConfigDataLocationResolver
的主要功能是解析外部配置文件
public class StandardConfigDataLocationResolver
implements ConfigDataLocationResolver<StandardConfigDataResource>, Ordered {
public StandardConfigDataLocationResolver(Log logger, Binder binder, ResourceLoader resourceLoader) {
// 加载 `spring.factories` 中的属性加载器,properties+yaml
this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
getClass().getClassLoader());
// 获取 `spring.config.name` 指定的应用名称,默认是 `application`
this.configNames = getConfigNames(binder);
// ... 代码省略
}
// 解析路径 location
@Override
public List<StandardConfigDataResource> resolve(ConfigDataLocationResolverContext context,
ConfigDataLocation location) throws ConfigDataNotFoundException {
// 获取数据引用,然后解析
return resolve(getReferences(context, location));
}
// 获取数据引用
private Set<StandardConfigDataReference> getReferences(ConfigDataLocationResolverContext context,
ConfigDataLocation configDataLocation) {
// 获取资源位置
String resourceLocation = getResourceLocation(context, configDataLocation);
try {
// 如果是目录,就按目录加载
if (isDirectory(resourceLocation)) {
// 加载目录下所有的 application*.[properties/yaml] 文件配置
return getReferencesForDirectory(configDataLocation, resourceLocation, NO_PROFILE);
}
// 不然就按文件加载,获取指定文件的引用
return getReferencesForFile(configDataLocation, resourceLocation, NO_PROFILE);
}
catch (RuntimeException ex) {
// ... 代码省略
}
}
// 解析路径 location 中指定profile的文件
@Override
public List<StandardConfigDataResource> resolveProfileSpecific(ConfigDataLocationResolverContext context,
ConfigDataLocation location, Profiles profiles) {
// 获取数据引用,然后解析
return resolve(getProfileSpecificReferences(context, location, profiles));
}
// 获取指定profile的数据引用
private Set<StandardConfigDataReference> getProfileSpecificReferences(ConfigDataLocationResolverContext context,
ConfigDataLocation configDataLocation, Profiles profiles) {
Set<StandardConfigDataReference> references = new LinkedHashSet<>();
// 获取资源位置
String resourceLocation = getResourceLocation(context, configDataLocation);
// 遍历profiles加载
for (String profile : profiles) {
references.addAll(getReferences(configDataLocation, resourceLocation, profile));
}
return references;
}
}
public class StandardConfigDataLocationResolver
implements ConfigDataLocationResolver<StandardConfigDataResource>, Ordered {
// 获取资源位置
private String getResourceLocation(ConfigDataLocationResolverContext context,
ConfigDataLocation configDataLocation) {
// 去掉"resource:"前缀
String resourceLocation = configDataLocation.getNonPrefixedValue(PREFIX);
// 如果是以 / 开头或者是 [protocol]: 开头的,就算是绝对路径,直接返回
boolean isAbsolute = resourceLocation.startsWith("/") || URL_PREFIX.matcher(resourceLocation).matches();
if (isAbsolute) {
return resourceLocation;
}
// 否则以相对路径对待,加载父路径前缀再返回
ConfigDataResource parent = context.getParent();
if (parent instanceof StandardConfigDataResource) {
String parentResourceLocation = ((StandardConfigDataResource) parent).getReference().getResourceLocation();
String parentDirectory = parentResourceLocation.substring(0, parentResourceLocation.lastIndexOf("/") + 1);
return parentDirectory + resourceLocation;
}
return resourceLocation;
}
// 解析StandardConfigDataReference为StandardConfigDataResource
private List<StandardConfigDataResource> resolve(Set<StandardConfigDataReference> references) {
List<StandardConfigDataResource> resolved = new ArrayList<>();
for (StandardConfigDataReference reference : references) {
resolved.addAll(resolve(reference));
}
if (resolved.isEmpty()) {
resolved.addAll(resolveEmptyDirectories(references));
}
return resolved;
}
}
3.2. StandardConfigDataLoader
StandardConfigDataLoader
的主要功能是读取外部配置文件里的值
public class StandardConfigDataLoader implements ConfigDataLoader<StandardConfigDataResource> {
// 加载文件为ConfigData
@Override
public ConfigData load(ConfigDataLoaderContext context, StandardConfigDataResource resource)
throws IOException, ConfigDataNotFoundException {
// ... 代码省略
StandardConfigDataReference reference = resource.getReference();
Resource originTrackedResource = OriginTrackedResource.of(resource.getResource(),
Origin.from(reference.getConfigDataLocation()));
String name = String.format("Config resource '%s' via location '%s'", resource,
reference.getConfigDataLocation());
// 读取为propertySources
List<PropertySource<?>> propertySources = reference.getPropertySourceLoader().load(name, originTrackedResource);
return new ConfigData(propertySources);
}
}
4. 应用运行监听器
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
EventPublishingRunListener
的主要功能是发布应用事件,调用事件监听函数
5. 错误报告器
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers
FailureAnalyzers
的主要功能是向用户报告程序错误
6. 应用上下文初始加载器
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
- ConfigurationWarningsApplicationContextInitializer
配置错误警告 - ContextIdApplicationContextInitializer
配置 ContextId - DelegatingApplicationContextInitializer
初始化context.initializer.classes
配置的类 - RSocketPortInfoApplicationContextInitializer
初始化local.rsocket.server.port
配置信息 - ServerPortInfoApplicationContextInitializer
初始化server.port
配置信息
这些类都比较简单,以 ConfigurationWarningsApplicationContextInitializer
为例解析
public class ConfigurationWarningsApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
// 初始化组件
@Override
public void initialize(ConfigurableApplicationContext context) {
context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));
}
protected static final class ConfigurationWarningsPostProcessor
implements PriorityOrdered, BeanDefinitionRegistryPostProcessor {
// bean定义后置处理
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
for (Check check : this.checks) {
// 如果 @ComponentScan 扫描了 org.springframework 或 org,则警告错误
String message = check.getWarning(registry);
if (StringUtils.hasLength(message)) {
warn(message);
}
}
}
}
}
7. 应用监听器
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
- ClearCachesApplicationListener
清除缓存 - ParentContextCloserApplicationListener
父上下文关闭 - FileEncodingApplicationListener
文件编码有误 - AnsiOutputApplicationListener
Ansi 输出 - DelegatingApplicationListener
代理context.listener.classes
配置的监听器 - LoggingApplicationListener
应用日志 - EnvironmentPostProcessorApplicationListener
触发 EnvironmentPostProcessor
组件
这些类都比较简单,可以自行探索
8. 环境后置处理器
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor,\
org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
8.1. CloudFoundryVcapEnvironmentPostProcessor
CloudFoundryVcapEnvironmentPostProcessor
的主要功能是支持 CloudFoundry(一个开源 PaaS 云平台)
8.2. ConfigDataEnvironmentPostProcessor
ConfigDataEnvironmentPostProcessor
的主要功能是加载和应用 ConfigData
到 Spring 环境中
public class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
postProcessEnvironment(environment, application.getResourceLoader(), application.getAdditionalProfiles());
}
void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader,
Collection<String> additionalProfiles) {
try {
// 获取资源加载器
resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
// 加载和应用
getConfigDataEnvironment(environment, resourceLoader, additionalProfiles).processAndApply();
}
catch (UseLegacyConfigProcessingException ex) {
// ... 代码省略
}
}
// 获取环境对象
ConfigDataEnvironment getConfigDataEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader,
Collection<String> additionalProfiles) {
return new ConfigDataEnvironment(this.logFactory, this.bootstrapContext, environment, resourceLoader,
additionalProfiles, this.environmentUpdateListener);
}
}
实际加载与应用是由 ConfigDataEnvironment
完成的
class ConfigDataEnvironment {
// 用于覆盖默认属性加载的地方
static final String LOCATION_PROPERTY = "spring.config.location";
// 默认之外,其他属性加载的地方
static final String ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location";
// 导入第三方属性文件
static final String IMPORT_PROPERTY = "spring.config.import";
// 默认属性加载的地方
// 1. 加载 classpath:/application*.yaml
// 2. 加载 classpath:/config/application*.yaml
// 3. 加载 file:./application*.yaml
// 4. 加载 file:./config/application*.yaml
// 5. 加载 file:./config/*/application*.yaml
static final ConfigDataLocation[] DEFAULT_SEARCH_LOCATIONS;
static {
List<ConfigDataLocation> locations = new ArrayList<>();
locations.add(ConfigDataLocation.of("optional:classpath:/"));
locations.add(ConfigDataLocation.of("optional:classpath:/config/"));
locations.add(ConfigDataLocation.of("optional:file:./"));
locations.add(ConfigDataLocation.of("optional:file:./config/"));
locations.add(ConfigDataLocation.of("optional:file:./config/*/"));
DEFAULT_SEARCH_LOCATIONS = locations.toArray(new ConfigDataLocation[0]);
}
// 属性值提供器
private final ConfigDataEnvironmentContributors contributors;
ConfigDataEnvironment(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment, ResourceLoader resourceLoader, Collection<String> additionalProfiles,
ConfigDataEnvironmentUpdateListener environmentUpdateListener) {
// ... 代码省略
// 创建默认的属性值提供器
this.contributors = createContributors(binder);
}
// 创建默认的属性值提供器
private ConfigDataEnvironmentContributors createContributors(Binder binder) {
// 获取属性值来源
MutablePropertySources propertySources = this.environment.getPropertySources();
// 结果集
List<ConfigDataEnvironmentContributor> contributors = new ArrayList<>(propertySources.size() + 10);
// 默认的属性值来源
PropertySource<?> defaultPropertySource = null;
for (PropertySource<?> propertySource : propertySources) {
// default properties
if (DefaultPropertiesPropertySource.hasMatchingName(propertySource)) {
defaultPropertySource = propertySource;
}
// 其他的
else {
contributors.add(ConfigDataEnvironmentContributor.ofExisting(propertySource));
}
}
// 获取默认的提供器
contributors.addAll(getInitialImportContributors(binder));
// 如果有默认的,添加到最后面
if (defaultPropertySource != null) {
contributors.add(ConfigDataEnvironmentContributor.ofExisting(defaultPropertySource));
}
// 创建 ConfigDataEnvironmentContributors
return createContributors(contributors);
}
// 获取默认的提供器
private List<ConfigDataEnvironmentContributor> getInitialImportContributors(Binder binder) {
// 结果集
List<ConfigDataEnvironmentContributor> initialContributors = new ArrayList<>();
// 添加 `spring.config.import` 指定的资源
addInitialImportContributors(initialContributors, bindLocations(binder, IMPORT_PROPERTY, EMPTY_LOCATIONS));
// 添加 `spring.config.additional-location` 指定的资源
addInitialImportContributors(initialContributors,
bindLocations(binder, ADDITIONAL_LOCATION_PROPERTY, EMPTY_LOCATIONS));
// 添加 `spring.config.location` 指定的资源
// (会覆盖默认属性加载的地方:classpath:/, classpath:/config/, file:./, file:./config/, file:./config/*/)
addInitialImportContributors(initialContributors,
bindLocations(binder, LOCATION_PROPERTY, DEFAULT_SEARCH_LOCATIONS));
return initialContributors;
}
}
class ConfigDataEnvironment {
// 处理及应用
void processAndApply() {
// 创建 ConfigDataImporter
ConfigDataImporter importer = new ConfigDataImporter(this.logFactory, this.notFoundAction, this.resolvers,
this.loaders);
// 绑定 contributors
registerBootstrapBinder(this.contributors, null, DENY_INACTIVE_BINDING);
// 导入 `spring.config.import` 指定的资源,重新绑定 contributors
ConfigDataEnvironmentContributors contributors = processInitial(this.contributors, importer);
// 创建一个配置数据激活上下文对象,如果绑定到了没有active的属性源,则报错
// 比如:spring.profiles.active=prod,但绑定了 application-dev.yaml
ConfigDataActivationContext activationContext = createActivationContext(
contributors.getBinder(null, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE));
// 导入无 profile `application.yaml` 的资源,重新绑定 contributors
contributors = processWithoutProfiles(contributors, importer, activationContext);
// 载入profiles到绑定的上下文中
activationContext = withProfiles(contributors, activationContext);
// 导入激活 profile `application-[active].yaml` 的资源,重新绑定 contributors
contributors = processWithProfiles(contributors, importer, activationContext);
// 应用到环境中
applyToEnvironment(contributors, activationContext);
}
// 导入 `spring.config.import` 指定的资源,重新绑定 contributors
private ConfigDataEnvironmentContributors processInitial(ConfigDataEnvironmentContributors contributors,
ConfigDataImporter importer) {
contributors = contributors.withProcessedImports(importer, null);
registerBootstrapBinder(contributors, null, DENY_INACTIVE_BINDING);
return contributors;
}
// 导入无 profile `application.yaml` 的资源,重新绑定 contributors
private ConfigDataEnvironmentContributors processWithoutProfiles(ConfigDataEnvironmentContributors contributors,
ConfigDataImporter importer, ConfigDataActivationContext activationContext) {
contributors = contributors.withProcessedImports(importer, activationContext);
registerBootstrapBinder(contributors, activationContext, DENY_INACTIVE_BINDING);
return contributors;
}
// 载入profiles到绑定的上下文中
private ConfigDataActivationContext withProfiles(ConfigDataEnvironmentContributors contributors,
ConfigDataActivationContext activationContext) {
// 获取绑定对象
Binder binder = contributors.getBinder(activationContext,
ConfigDataEnvironmentContributor::isNotIgnoringProfiles, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE);
try {
// 参数输入的profiles
Set<String> additionalProfiles = new LinkedHashSet<>(this.additionalProfiles);
// 载入当前激活环境中 `spring.profiles.include` 指定的其他环境
additionalProfiles.addAll(getIncludedProfiles(contributors, activationContext));
// 创建 Profiles 对象,载入到上下文中
Profiles profiles = new Profiles(this.environment, binder, additionalProfiles);
return activationContext.withProfiles(profiles);
}
catch (BindException ex) {
// ... 代码省略
}
}
// 导入激活 profile `application-[active].yaml` 的资源,重新绑定 contributors
private ConfigDataEnvironmentContributors processWithProfiles(ConfigDataEnvironmentContributors contributors,
ConfigDataImporter importer, ConfigDataActivationContext activationContext) {
contributors = contributors.withProcessedImports(importer, activationContext);
registerBootstrapBinder(contributors, activationContext, ALLOW_INACTIVE_BINDING);
return contributors;
}
// 应用到环境中
private void applyToEnvironment(ConfigDataEnvironmentContributors contributors,
ConfigDataActivationContext activationContext) {
// ... 代码省略
// 属性来源
MutablePropertySources propertySources = this.environment.getPropertySources();
// 遍历contributors
for (ConfigDataEnvironmentContributor contributor : contributors) {
PropertySource<?> propertySource = contributor.getPropertySource();
// ... 代码省略
// 如果是激活的,加入到环境的propertySources中
if (contributor.isActive(activationContext)) {
propertySources.addLast(propertySource);
}
}
// ... 代码省略
}
}
实际资源载入是由 ConfigDataEnvironmentContributors
完成的
class ConfigDataEnvironmentContributors implements Iterable<ConfigDataEnvironmentContributor> {
// 处理载入属性值
ConfigDataEnvironmentContributors withProcessedImports(ConfigDataImporter importer,
ConfigDataActivationContext activationContext) {
// 每次载入新的文件后,都返回一个新的对象
ConfigDataEnvironmentContributors result = this;
int processed = 0;
while (true) {
// 获取下一个可以载入的文件
ConfigDataEnvironmentContributor contributor = getNextToProcess(result, activationContext, importPhase);
// 没有下一个了,返回
if (contributor == null) {
return result;
}
// 非导入其他文件
if (contributor.getKind() == Kind.UNBOUND_IMPORT) {
// 配置属性源
Iterable<ConfigurationPropertySource> sources = Collections
.singleton(contributor.getConfigurationPropertySource());
// 占位符解析器
PlaceholdersResolver placeholdersResolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(
result, activationContext, true);
// 新建绑定
Binder binder = new Binder(sources, placeholdersResolver, null, null, null);
// 生成一个新的ConfigDataEnvironmentContributor
ConfigDataEnvironmentContributor bound = contributor.withBoundProperties(binder);
// 生成一个新的对象
result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext,
result.getRoot().withReplacement(contributor, bound));
continue;
}
// 路径解析上下文
ConfigDataLocationResolverContext locationResolverContext = new ContributorConfigDataLocationResolverContext(
result, contributor, activationContext);
// 加载上下文
ConfigDataLoaderContext loaderContext = new ContributorDataLoaderContext(this);
// 获取导入的资源路径
List<ConfigDataLocation> imports = contributor.getImports();
// 导入资源为ConfigData
Map<ConfigDataResolutionResult, ConfigData> imported = importer.resolveAndLoad(activationContext,
locationResolverContext, loaderContext, imports);
// 合并当前与上一次的属性值
ConfigDataEnvironmentContributor contributorAndChildren = contributor.withChildren(importPhase,
asContributors(imported));
// 生成一个新的对象
result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext,
result.getRoot().withReplacement(contributor, contributorAndChildren));
processed++;
}
}
}
8.3. CloudFoundryVcapEnvironmentPostProcessor
CloudFoundryVcapEnvironmentPostProcessor
的主要功能是支持以random.
开头的属性配置转换成实际的随机值
8.4. SpringApplicationJsonEnvironmentPostProcessor
SpringApplicationJsonEnvironmentPostProcessor
的主要功能是支持用 spring.application.json
参数或 SPRING_APPLICATION_JSON
环境变量作为初始化参数传入 JSON 数据
public class SpringApplicationJsonEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
// 获取属性来源
MutablePropertySources propertySources = environment.getPropertySources();
// 流式处理 `spring.application.json` 参数或 `SPRING_APPLICATION_JSON` 环境变量
propertySources.stream().map(JsonPropertyValue::get).filter(Objects::nonNull).findFirst()
.ifPresent((v) -> processJson(environment, v));
}
private void processJson(ConfigurableEnvironment environment, JsonPropertyValue propertyValue) {
// 获取JSON解析器
JsonParser parser = JsonParserFactory.getJsonParser();
// 解析成Map
Map<String, Object> map = parser.parseMap(propertyValue.getJson());
// 有值
if (!map.isEmpty()) {
// 添加为一个JSON来源
addJsonPropertySource(environment, new JsonPropertySource(propertyValue, flatten(map)));
}
}
}
public abstract class JsonParserFactory {
public static JsonParser getJsonParser() {
// 默认首先使用Jackson
if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", null)) {
return new JacksonJsonParser();
}
// 其次使用Gson
if (ClassUtils.isPresent("com.google.gson.Gson", null)) {
return new GsonJsonParser();
}
// 其次使用Yaml
if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {
return new YamlJsonParser();
}
// 都没有,使用内置的
return new BasicJsonParser();
}
}
8.5. SystemEnvironmentPropertySourceEnvironmentPostProcessor
SystemEnvironmentPropertySourceEnvironmentPostProcessor
的主要功能是处理 systemEnvironment
属性来源
8.6. DebugAgentEnvironmentPostProcessor
DebugAgentEnvironmentPostProcessor
的主要功能是处理 spring.reactor.debug-agent.enabled
9. 失败分析器
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.context.config.ConfigDataNotFoundFailureAnalyzer,\
org.springframework.boot.context.properties.IncompatibleConfigurationFailureAnalyzer,\
org.springframework.boot.context.properties.NotConstructorBoundInjectionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PatternParseFailureAnalyzer,\
org.springframework.boot.liquibase.LiquibaseChangelogMissingFailureAnalyzer
- ConfigDataNotFoundFailureAnalyzer
无ConfigData
- IncompatibleConfigurationFailureAnalyzer
不兼容的配置 - NotConstructorBoundInjectionFailureAnalyzer
没有绑定注入 bean 的实例化 - BeanCurrentlyInCreationFailureAnalyzer
bean 正在创建 - BeanDefinitionOverrideFailureAnalyzer
bean 定义被覆盖重写 - BeanNotOfRequiredTypeFailureAnalyzer
bean 不是指定类型 - BindFailureAnalyzer
绑定属性值失败 - BindValidationFailureAnalyzer
绑定验证失败 - UnboundConfigurationPropertyFailureAnalyzer
更新解绑配置失败 - ConnectorStartFailureAnalyzer
tomcat 链接失败 - NoSuchMethodFailureAnalyzer
没有方法 - NoUniqueBeanDefinitionFailureAnalyzer
不是唯一的 bean 定义 - PortInUseFailureAnalyzer
端口已被占用 - ValidationExceptionFailureAnalyzer
数据验证失败 - InvalidConfigurationPropertyNameFailureAnalyzer
不合法配置属性名 - InvalidConfigurationPropertyValueFailureAnalyzer
不合法配置属性值 - PatternParseFailureAnalyzer
正则解析失败 - LiquibaseChangelogMissingFailureAnalyzer
Liquibase changelog 不存在
这些类都比较简单,可以自行探索
10. 失败分析报告器
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
LoggingFailureAnalysisReporter
的主要功能是应用启动失败,报告原因 APPLICATION FAILED TO START
后续
更多博客,查看 https://github.com/senntyou/blogs
版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。