SpringBoot源码 - run方法启动流程

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

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

run方法主要干了两件事,一件是创建 SpringApplication 并进行初始化,初始化如下图:

创建SpringApplication对象并初始化.jpg

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

run过程.jpg

这个就是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方法:

prepareEnvironment方法.jpg

准备系统环境:

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主流程中:

prepareEnvironment之后.jpg
  • configureIgnoreBeanInfo
configureIgnoreBeanInfo.jpg

设置忽略掉的bean

  • 接下来是打印 banner:

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

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

prepareContext.jpg

具体如下:

// 将环境变量设置到容器中
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;
    

    总流程图如下:


    run流程.png

你可能感兴趣的:(SpringBoot源码 - run方法启动流程)