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

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 内置反对 logbacklogbackjava原生三种日志解决,具体源代码能够自行摸索

  • LogbackLoggingSystem
  • Log4J2LoggingSystem
  • JavaLoggingSystem

2. 属性起源加载器

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

配置中阐明 SpringBoot 内置反对 application*.propertiesapplication*.yaml 两种文件格式加载属性配置起源,具体源代码能够自行摸索

  • PropertiesPropertySourceLoader
  • YamlPropertySourceLoader

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
    配置谬误正告
  • 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

作者:深予之 (@senntyou)

版权申明:自在转载-非商用-非衍生-放弃署名(创意共享 3.0 许可证)

【腾讯云】轻量 2核2G4M,首年65元

阿里云限时活动-云数据库 RDS MySQL  1核2G配置 1.88/月 速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据