Spring 源码解析十三:SpringBoot 初始化应用时加载的组件

x33g5p2x  于2022-02-11 发布在 Spring  
字(27.6k)|赞(0)|评价(0)|浏览(493)

这些组件定义在 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 内置支持 logbacklogbackjava原生三种日志处理,具体源代码可以自行探索

2. 属性来源加载器

org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

配置中说明 SpringBoot 内置支持 application*.propertiesapplication*.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

这一组放在一起解析,是因为他们一起完成了一个功能:

  1. ConfigDataLocationResolver
    spring.config.importspring.config.addtional-locationspring.config.location 等资源定位路径下的
    application*.[properties/yaml] 资源解析成 ConfigDataResource
    资源对象,等待加载
  2. ConfigDataLoader
    将解析好的资源对象进行加载,把 ConfigDataResource 转换成 ConfigData
    ConfigData 是一组 PropertySource
  3. 将加载好的 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
为例解析

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

这些类都比较简单,可以自行探索

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

这些类都比较简单,可以自行探索

10. 失败分析报告器

org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

LoggingFailureAnalysisReporter
的主要功能是应用启动失败,报告原因 APPLICATION FAILED TO START

后续

更多博客,查看 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证

相关文章