SpringBoot源码 - run方法启动流程

我们从主方法启动的入口开始,如下:

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

run方法主要干了两件事,一件是创建 SpringApplication 并进行初始化,初始化如下图:
SpringBoot源码 - run方法启动流程
文章图片

另一件是run的执行,我们重点看run的执行流程,一路点击run方法,直到:
SpringBoot源码 - 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方法:
SpringBoot源码 - run方法启动流程
文章图片

准备系统环境:
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主流程中:
SpringBoot源码 - run方法启动流程
文章图片

  • configureIgnoreBeanInfo
SpringBoot源码 - run方法启动流程
文章图片

设置忽略掉的bean
  • 接下来是打印 banner:
    Banner printedBanner = this.printBanner(environment);

  • 【SpringBoot源码 - run方法启动流程】接着这一步比较重要,就是创建容器:
    context = this.createApplicationContext();

  • 接下来是prepareContext方法
SpringBoot源码 - run方法启动流程
文章图片

具体如下:
// 将环境变量设置到容器中 context.setEnvironment(environment); // 对 ApplicationContext进行后置处理,设置beanNameGenerator、resourceLoader、classLoader和conversionService this.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 sources = this.getAllSources(); this.load(context, sources.toArray(new Object[0])); //触发监听器,调用每个 SpringApplicationRunListerner 的 contextLoaded 方法 listeners.contextLoaded(context);
  • refreshContext 刷新容器,完成组件的扫描、创建、加载等
    this.refreshContext(context);

  • 返回容器
    return context;

    总流程图如下:
    SpringBoot源码 - run方法启动流程
    文章图片

    推荐阅读