springboot加载application文件过程

100 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

现在开发主要使用微服务框架springboot,在springboot中经常遇到读取application.yml文件的情形。

使用它的过程代码也比较简单,使用@Value注解既可以完成调用,示例如下:

@Value("${spring.mail.username}")
private String userName;

但是之前从来没有了解过SpringBoot加载配置文件的过程。今天我也来学习下入口加载配置文件。

加载监听器

依旧是通过SpringApplication的启动过程去跟踪,启动时跟踪run方法,可以看到在SpringApplication.class文件中的run方法

​
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        //加载监听器
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();
            Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
           // 加载SpringBoot配置环境
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
​
            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }
​
        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

这个过程,应用的监听器SpringApplicationRunListeners并开始监听,通过prepareEnvironment方法准备environment的配置信息,,其中加载配置文件的监听器就在循环列表中,加载SpringBoot配置环境(ConfigurableEnvironment),在prepareEnvironment方法中会执行EventPublishingRunListener中的environmentPrepared()方法,

public void environmentPrepared(ConfigurableEnvironment environment) {
        this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
    }

initialMulticaster可以找到SimpleApplicationEventMulticaster类中的doInvokeListener()方法,进入到ConfigFiledApplicationListerner类中,执行onApplicationEnviromentPrepareEvent()方法,

image.png

重点看ConfigFileApplicationListener类中的postProcessEnvironment方法,其中会添加一个属性源进来ResourceLoader,会调用load方法加载属性,

image.png

进入load方法,执行一个初始化方法initializeProfiles,方法中会向profiles中放入null,然后再放入一个"default",用来从外部遍历,遍历为null的时候,加载springboot的默认配置,遍历为“default"时,加载用户配置。

执行getSearchLocations方法,获取默认的路径classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/

获取配置文件名字,如果配置spring.confing.name的话,则去配置的名字,否则用默认的"application"

image.png

image.png

最终通过以钩子程序的形式调用函数式编程完成属性的赋值。

image.png 好了,本文就给大家介绍到这里,感觉有帮助的,留下个赞或评论再走吧!谢啦~ 💐