美文网首页我爱编程
Spring Boot启动分析

Spring Boot启动分析

作者: simoscode | 来源:发表于2018-04-14 10:33 被阅读125次

1前言

这篇主要讲讲springboot应用(使用的版本是:2.0.1.RELEASE)启动过程.

2启动过程分析

启动springboot应用最简单方式,只有一行代码如下所示

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

SpringApplication类的注释里说明它的作用,在java的main方法里构建,启动一个spring 应用.默认情况下执行以下几个步骤来构建我们的应用:

  • 根据classpath创建一个ApplicationContext实例
  • 注册一个CommandLinePropertySource将命令行参数保存起来作为spring properties
  • refresh ApplicationContext ,加载所有的单例bean
  • 触发ApplicationRunner or CommandLineRunnerbean的run方法调用.官方文档传送门CommandLineRunner使用
    接下来看看源码里头怎么实现以上四个步骤的.

2.1初始化SpringApplication

SpringApplication调用静态方法run(),这个静态方法先实例化一个SpringApplication,然后再执行具体的run()方法.代码截图如下:

静态方法run
在SpringApplication构造函数中,初始化了几个属性.源码如下:
   public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //推测应用类型
    this.webApplicationType = deduceWebApplicationType();
    //通过SpringFactoriesLoader从/META-INF/spring.factories获取ApplicationContextInitializer信息,
       并实例化ApplicationContextInitializer
    setInitializers((Collection) getSpringFactoriesInstances(
            ApplicationContextInitializer.class));
     //通过SpringFactoriesLoader从/META-INF/spring.factories获取ApplicationListener信息,并实例化ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
     //判断传入primarySources类是否包含main方法
    this.mainApplicationClass = deduceMainApplicationClass();
}

2.2非静态run方法调用

在2.1中介绍了SpringApplication的初始化过程.接下来就看看run方法都干了啥.

public ConfigurableApplicationContext run(String... args) {
     //定义StopWatch,用于监控应用启动耗时,分析性能
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
   //获取一个SpringApplicationRunListeners 实例,监控spring应用启动的执行过程,并发布相应事件(starting,environmentPrepared,contextPrepared,contextLoaded,started,running,failed)
    SpringApplicationRunListeners listeners = getRunListeners(args);
     //正在启动
    listeners.starting();
    try {
                   //保存传递过来的命令行参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);
        //根据webApplicationType类型得到ConfigurableEnvironment
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);
        configureIgnoreBeanInfo(environment);
        //打印banner,就启动的时候那个超级大的'spring'.如果想自定义,只需要把对应banner.txt
           (需要打印的内容,网上有不少在线生成banner样式的网站)放置resource目录即可
        Banner printedBanner = printBanner(environment);
        //根据webApplicationType创建applicationcontext
        context = createApplicationContext();
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
       //context预处理,设置Environment
        prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);
       //最核心的一步:加载,生成各种自动化配置bean,它调用栈如图2所示,最终调用到@EnableAutoConfiguration里@import AutoConfigurationImportSelector
        refreshContext(context);
        afterRefresh(context, applicationArguments);
      //停止监控
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);
        }
          //发布启动事件
        listeners.started(context);
        //调用runner  
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {
         //发布context正在运行事件
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}
stack.png

3小结

从上面的源码可以看出,springboot启动的时候,主要干了一件事:完成ApplicationContext的创建以及bean创建.

相关文章

网友评论

    本文标题:Spring Boot启动分析

    本文链接:https://www.haomeiwen.com/subject/usuckftx.html