美文网首页我爱编程
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