咱们从主办法启动的入口开始,如下:

public static void main(String[] args) {    SpringApplication.run(DemoApplication.class, args);}

run办法次要干了两件事,一件是创立 SpringApplication 并进行初始化,初始化如下图:

另一件是run的执行,咱们重点看run的执行流程,一路点击run办法,直到:

这个就是run办法启动的主流程了,上面一步步来看:

  • 创立秒表计时器,开始计时

    StopWatch stopWatch = new StopWatch();stopWatch.start();
  • 配置Headless属性

    private void configureHeadlessProperty() {              System.setProperty("java.awt.headless",      System.getProperty("java.awt.headless",    Boolean.toString(this.headless)));}
    这里同一个属性,取了有设置回去,看起来截然不同,其实是因为 getProperty带两个参数的时候,会给默认值,所以再设置一次就能保障该属性都有值
  • 从META-INF/spring.factories找到所有SpringApplicationRunListener的监听器,启动监听器

    SpringApplicationRunListeners listeners = this.getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);
  • 配置环境 ConfigurableEnvironment,退出到监听器对象中

    ConfigurableEnvironment environment = this.prepareEnvironment(listeners,                                                     bootstrapContext, applicationArguments);

    点击prepareEnvironment办法进去,办法里首先创立环境对象:

    ConfigurableEnvironment environment = this.getOrCreateEnvironment();

    接着配置环境:

    this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());

    而 configureEnvironment()办法,会进行以下两个操作:

    // 加载配置源参数和命令行属性this.configurePropertySources(environment, args);// 配置以后activede的形容文件this.configureProfiles(environment, args);

    回到prepareEnvironment办法:

筹备零碎环境:

listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);

接下来bindToSpringApplication()办法:

protected void bindToSpringApplication(ConfigurableEnvironment environment) {        try {            Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));        } catch (Exception var3) {            throw new IllegalStateException("Cannot bind to SpringApplication", var3);        }    }

将配置文件中的spring.main结尾的配置信息绑定到SpringApplication类对应的属性中。

再回到run主流程中:

  • configureIgnoreBeanInfo

设置疏忽掉的bean

  • 接下来是打印 banner:

    Banner printedBanner = this.printBanner(environment);
  • 接着这一步比拟重要,就是创立容器:

    context = this.createApplicationContext();
  • 接下来是prepareContext办法

具体如下:

// 将环境变量设置到容器中context.setEnvironment(environment);// 对 ApplicationContext进行后置解决,设置beanNameGenerator、resourceLoader、classLoader和conversionServicethis.postProcessApplicationContext(context);// 获取之前获取到的所有 initializer 类型的类,并进行初始化this.applyInitializers(context);// 告诉监听器context筹备实现listeners.contextPrepared(context);// 打印profile信息this.logStartupProfileInfo(context);   // 注册一个利用参数实例ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();   beanFactory.registerSingleton("springApplicationArguments", applicationArguments);// 注册 printedBanner实例beanFactory.registerSingleton("springBootBanner", printedBanner);// 设置是否容许同名bean,默认false((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);// 获取,加载启动类,注入到容器中Set<Object> sources = this.getAllSources();this.load(context, sources.toArray(new Object[0]));//触发监听器,调用每个 SpringApplicationRunListerner 的 contextLoaded 办法listeners.contextLoaded(context);
  • refreshContext 刷新容器,实现组件的扫描、创立、加载等

    this.refreshContext(context);
  • 返回容器

    return context;

    总流程图如下: