Spring Boot-源码阅读-如何加载环境变量(二)

说明

在Spring Boot-源码阅读-启动主流程(一) 8-11处触发了环境变量的加载

 

<1>

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                       DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
        // <2>内部封装的PropertySource集合 封装各个环境变量 如默认会初始化系统环境变量 和jvm环境变量
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        //将系统变量设置到environment
        configureEnvironment(environment, applicationArguments.getSourceArgs());      
        ConfigurationPropertySources.attach(environment);
        //<4>发送listener ApplicationEnviromentPreparedEvent 对应消费将触发我们application.yml配置文件加载
        /**
         * # Run Listeners
         * org.springframework.boot.SpringApplicationRunListener=\
         * org.springframework.boot.context.event.EventPublishingRunListener 默认
         */
        listeners.environmentPrepared(bootstrapContext, environment);
        DefaultPropertiesPropertySource.moveToEnd(environment);
        Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
                "Environment prefix cannot be set via properties.");
        bindToSpringApplication(environment);
        if (!this.isCustomEnvironment) {
            environment = convertEnvironment(environment);
        }
        ConfigurationPropertySources.attach(environment);
        return environment;
    }

<2>

private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        }
        switch (this.webApplicationType) {
            case SERVLET:
                 //<3>默认返回此 父类会触发初始化默认的PropertySource
                return new ApplicationServletEnvironment();
            case REACTIVE:
                return new ApplicationReactiveWebEnvironment();
            default:
                return new ApplicationEnvironment();
        }
    }

<3>

继承链

 

 

 org.springframework.core.env.AbstractEnvironment

    public AbstractEnvironment() {
        this(new MutablePropertySources());
    }
    protected AbstractEnvironment(MutablePropertySources propertySources) {
        this.propertySources = propertySources;
//当我调用get 就是委托给Resolver 遍历调用propertSource获取对应的值。比如我们可以实现自定义key解析 get("${age}")内部委托给propertySroce就传age
this.propertyResolver = createPropertyResolver(propertySources); //<3-1>被子类重写 StandardServletEnvironment customizePropertySources(propertySources); }

<3-1>

org.springframework.web.context.support.StandardServletEnvironment#customizePropertySources

 public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
    public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
    protected void customizePropertySources(MutablePropertySources propertySources) {
        //新增2个servlet相关的propertySource 但是是空的
        propertySources.addLast(new PropertySource.StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
        propertySources.addLast(new PropertySource.StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
        if (jndiPresent && JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
            propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
        }
        //<3-2>调用父类StandardEnvironment 的自定义方法
        super.customizePropertySources(propertySources);
    }

<3-2>

org.springframework.core.env.StandardEnvironment#customizePropertySources

 public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
    public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
    @Override
    protected void customizePropertySources(MutablePropertySources propertySources) {
        //新增2各个System相关环境变量 并加载
        //内部调用System.getProperties() 获得map jvm参数相关环境变量
        propertySources.addLast(
                new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
        //内部调用 (Map) System.getenv() 获得map 主要获取系统相关环境变量
        propertySources.addLast(
                new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
    }

<4>

  //EventPublishingRunListener构造函数
    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        //EventPublishingRunListener初始化的时候会初始化一个广播器,注册了我们ApplicationListener监听器 初始化处可以查看<点击跳转>
        for (ApplicationListener<?> listener : application.getListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
        }
    }
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
                                    ConfigurableEnvironment environment) {
        //<5>发送ApplicationEnvironmentPreparedEvent事件 将由监听器org.springframework.boot.env.EnvironmentPostProcessorApplicationListener监听处理
        this.initialMulticaster.multicastEvent(
                new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
    }

<5>

我们主要关注org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor 这个就是如何加载application.yml

org.springframework.boot.env.EnvironmentPostProcessorApplicationListener#onApplicationEnvironmentPreparedEvent

    private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        ConfigurableEnvironment environment = event.getEnvironment();
        SpringApplication application = event.getSpringApplication();
        //<6>这里也是获取spring.factories的EnvironmentPostProcessor实现类 这里也是我们加载自定义环境变量的扩展点
        /**
         * # Environment Post Processors
         * org.springframework.boot.env.EnvironmentPostProcessor=\
         * org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
         * org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor,\
         * org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor,\ 针对于随机数可以自行百度 如@value(${random.int}),@value(${random.int[1,1024]}),
         * org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\ 针对json的配置如:-d {"age":12} @value(${age})
         * org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
         * org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
         */
        for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(),
                event.getBootstrapContext())) {
            postProcessor.postProcessEnvironment(environment, application);
        }
    }

<6>

org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor#postProcessEnvironment

 @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        postProcessEnvironment(environment, application.getResourceLoader(), application.getAdditionalProfiles());
    }
    void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader,
                                Collection<String> additionalProfiles) {
        try {
            this.logger.trace("Post-processing environment to add config data");
            resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
            //委托给ConfigDataEnvironment 触发加载<7>初始化 <10>加载
            getConfigDataEnvironment(environment, resourceLoader, additionalProfiles).processAndApply();
        }
        catch (UseLegacyConfigProcessingException ex) {
            this.logger.debug(LogMessage.format("Switching to legacy config file processing [%s]",
                    ex.getConfigurationProperty()));
            configureAdditionalProfiles(environment, additionalProfiles);
            postProcessUsingLegacyApplicationListener(environment, resourceLoader);
        }
    }

<7>

org.springframework.boot.context.config.ConfigDataEnvironment#ConfigDataEnvironment

    ConfigDataEnvironment(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,
                          ConfigurableEnvironment environment, ResourceLoader resourceLoader, Collection<String> additionalProfiles,
                          ConfigDataEnvironmentUpdateListener environmentUpdateListener) {
        Binder binder = Binder.get(environment);
        UseLegacyConfigProcessingException.throwIfRequested(binder);
        this.logFactory = logFactory;
        this.logger = logFactory.getLog(getClass());
        this.notFoundAction = binder.bind(ON_NOT_FOUND_PROPERTY, ConfigDataNotFoundAction.class)
                .orElse(ConfigDataNotFoundAction.FAIL);
        this.bootstrapContext = bootstrapContext;
        this.environment = environment;
        this.resolvers = createConfigDataLocationResolvers(logFactory, bootstrapContext, binder, resourceLoader);
        this.additionalProfiles = additionalProfiles;
        this.environmentUpdateListener = (environmentUpdateListener != null) ? environmentUpdateListener
                : ConfigDataEnvironmentUpdateListener.NONE;
        this.loaders = new ConfigDataLoaders(logFactory, bootstrapContext, resourceLoader.getClassLoader());
        //<8>我的理解这个是解析器
        this.contributors = createContributors(binder);
    }

<8>

org.springframework.boot.context.config.ConfigDataEnvironment#createContributors

   private ConfigDataEnvironmentContributors createContributors(Binder binder) {
        this.logger.trace("Building config data environment contributors");
        MutablePropertySources propertySources = this.environment.getPropertySources();
        List<ConfigDataEnvironmentContributor> contributors = new ArrayList<>(propertySources.size() + 10);
        PropertySource<?> defaultPropertySource = null;
        for (PropertySource<?> propertySource : propertySources) {
            if (DefaultPropertiesPropertySource.hasMatchingName(propertySource)) {
                defaultPropertySource = propertySource;
            }
            else {
                this.logger.trace(LogMessage.format("Creating wrapped config data contributor for '%s'",
                        propertySource.getName()));
                contributors.add(ConfigDataEnvironmentContributor.ofExisting(propertySource));
            }
        }
        //<9>主要是这里创建负责解析指定目录文件下配置文件的解析器
        contributors.addAll(getInitialImportContributors(binder));
        if (defaultPropertySource != null) {
            this.logger.trace("Creating wrapped config data contributor for default property source");
            contributors.add(ConfigDataEnvironmentContributor.ofExisting(defaultPropertySource));
        }
        return createContributors(contributors);
    }

<9>

org.springframework.boot.context.config.ConfigDataEnvironment#getInitialImportContributors

 static final ConfigDataLocation[] DEFAULT_SEARCH_LOCATIONS;
    static {
        List<ConfigDataLocation> locations = new ArrayList<>();
        locations.add(ConfigDataLocation.of("optional:classpath:/;optional:classpath:/config/"));
        locations.add(ConfigDataLocation.of("optional:file:./;optional:file:./config/;optional:file:./config/*/"));
        DEFAULT_SEARCH_LOCATIONS = locations.toArray(new ConfigDataLocation[0]);
    }

    private List<ConfigDataEnvironmentContributor> getInitialImportContributors(Binder binder) {
        List<ConfigDataEnvironmentContributor> initialContributors = new ArrayList<>();
        addInitialImportContributors(initialContributors, bindLocations(binder, IMPORT_PROPERTY, EMPTY_LOCATIONS));
        addInitialImportContributors(initialContributors,
                bindLocations(binder, ADDITIONAL_LOCATION_PROPERTY, EMPTY_LOCATIONS));
        //主要是这里新增了从哪些目录下查找我们的properties文件 指定定义还未加载
        addInitialImportContributors(initialContributors,
                bindLocations(binder, LOCATION_PROPERTY, DEFAULT_SEARCH_LOCATIONS));
        return initialContributors;
    }

<10>

org.springframework.boot.context.config.ConfigDataEnvironment#processAndApply

    void processAndApply() {
        ConfigDataImporter importer = new ConfigDataImporter(this.logFactory, this.notFoundAction, this.resolvers,
                this.loaders);
        registerBootstrapBinder(this.contributors, null, DENY_INACTIVE_BINDING);
        //这里先加载我们的application.yml文件
        ConfigDataEnvironmentContributors contributors = processInitial(this.contributors, importer);
        ConfigDataActivationContext activationContext = createActivationContext(
                contributors.getBinder(null, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE));
        //根据application.yml配置的环境,加载对应的yml文件
        /**
         * 如
         * spring:
         *   profiles:
         *     active: dev,test
         */
        contributors = processWithoutProfiles(contributors, importer, activationContext);
        //解析出环境配置如 dev,test
        activationContext = withProfiles(contributors, activationContext);
        //进行对应环境的yml文件加载
        contributors = processWithProfiles(contributors, importer, activationContext);
        //转成PropertySource add到Environment
        applyToEnvironment(contributors, activationContext, importer.getLoadedLocations(),
    }

 

posted @ 2022-02-26 14:38  意犹未尽  阅读(1069)  评论(1编辑  收藏  举报