springboot啓動流程簡析

Spring Boot能夠輕鬆建立獨立的,生產級的基於Spring的應用程序,而這隻須要不多的一些Spring配置。本文將從SpringBoot的啓動流程角度簡要的分析SpringBoot啓動過程當中主要作了哪些事情。java

說明: springboot 2.0.6.RELEASEweb


SpringBoot啓動簡要流程圖

SpringBoot啓動流程

原始大圖連接redis

啓動流程概述

啓動流程從角度來看,主要分兩個步驟。第一個步驟是構造一個SpringApplication應用,第二個步驟是調用它的run方法,啓動應用。spring

1 構造SpringApplication應用

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        //資源加載器默認爲null
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        //primarySources這裏指的是執行main方法的主類
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        //根據classpath推斷出應用類型,主要有NONE,SERVLET,REACTIVE三種類型
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //經過SpringFactoriesLoader工具類獲取META-INF/spring.factories中配置的一系列
        //ApplicationContextInitializer接口的子實現類
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        //基本同上,也是經過SpringFactoriesLoader工具類獲取配置的ApplicationListener
        //接口的子實現類
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        //經過方法調用堆棧獲取到main執行方法的主類
        this.mainApplicationClass = deduceMainApplicationClass();
    }

SpringApplication的構造函數中爲SpringApplication作了一些初始化配置,包括
主資源類(通常是啓動類 primarySources )、
應用類型(webApplicationType )、
應用環境上下文初始化器(initializers)、
應用監聽器(listeners)、
main方法主類(mainApplicationClass )springboot

initializers將在ConfigurableApplicationContext的refresh方法以前調用,好比針對web應用來講,須要在refresh以前註冊屬性源或者激活指定的配置文件。app

listeners將在AbstractApplicationContext的refresh()方法中,先被註冊到IOC容器中,IOC容器中剩下的非懶加載的單例被實例化後,IOC容器發佈相應的事件,這些事件最終會調用與之相關聯的AplicationListener的onApplicationEvent方法less

可對照文章頂部的流程圖和源碼分析函數


2 運行SpringApplication運行

/**建立並刷新應用上下文**/
    public ConfigurableApplicationContext run(String... args) {
        //spring-core包下的計時器類,在這裏主要用來記錄應用啓動的耗時
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        
        //系統配置設置爲headless模式
        configureHeadlessProperty();
        //經過SpringFactoriesLoader工具類獲取META-INF/spring.factories
        //文件中SpringApplicationRunListeners接口的實現類,在這裏是
        //EventPublishingRunListener
        SpringApplicationRunListeners listeners = getRunListeners(args);
        
        //廣播ApplicationStartingEvent事件使應用中的ApplicationListener
        //響應該事件
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            //準備應用環境,這裏會發佈ApplicationEnvironmentPreparedEvent事件
            //並將environment綁定到SpringApplication中
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            
            configureIgnoreBeanInfo(environment);
            //打印彩蛋
            Banner printedBanner = printBanner(environment);
            //根據成員變量webApplicationType建立應用上下文
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            //準備上下文,見文章頂部流程圖
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            //刷新上下文,見文章頂部流程圖
            refreshContext(context);
            //上下文後處理,空實現
            afterRefresh(context, applicationArguments);
            //計時中止
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            //廣播ApplicationStartedEvent事件使應用中的ApplicationListener
            //響應該事件
            listeners.started(context);
            
            //應用上下文中的ApplicationRunner,CommandLineRunner執行run方法
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            //廣播ApplicationReadyEvent事件使應用中的ApplicationListener
            //響應該事件     
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        //返回應用上下文
        return context;
    }
  • 在啓動過程當中,SpringApplicationListener在不一樣階段經過調用自身的不一樣方法(如starting()、environmentPrepared())發佈相應事件,通知ApplicationListener進行響應。spring-boot

  • refreshContext(context)方法是構建IOC容器最複雜的一步,絕大多數bean的定義加載以及實例化都在這一步執行。包括但不限於BeanFactoryPostProcessor、BeanPostProcessor、ApplicationEventMulticaster、@Controller,@Component等註解的組件。工具

  • SpringFactoriesLoader工具類,在SpringApplication的構造過程當中、運行過程當中都起到了極其重要的做用。SpringBoot的自動化配置功能一個核心依賴點就在該類上,該類經過讀取類路徑下的META-INF/spring.factories文件獲取各類各樣的工廠接口的實現類,經過反射獲取這些類的類對象、構造方法,最終生成實例。

總結

  1. SpringApplication的構造過程當中,配置了SpringApplication應用上下文的一些基本元素,如應用類型webApplicationType、應用初始化器ApplicationContextInitializer、應用監聽器ApplicationListener等。這些元素在SpringApplication的執行run()過程當中,都會在不一樣階段發揮不一樣的做用
  2. SpringApplication的執行run()過程當中,一方面要初始化IOC容器(主要是bean的加載與初始化),一方面要在不一樣的階段直接或間接回調ApplicationListener或ApplicationRunner等其餘接口的方法
  3. SpringFactoriesLoader是SpringBoot自動化配置功能極其關鍵的一環,它讀取類路徑下META-INF/spring.factories文件中工廠接口的實現類,來獲取各類各類的Bean工廠實例,最終獲取到自動化配置的bean。

備註:下一篇將經過spring-boot-starter-data-redis來分析SpringBoot對redis的自動化配置是如何操做的,以及SpringFactoriesLoader在SpringApplication啓動過程當中的各個階段時發揮了什麼做用?

相關文章
相關標籤/搜索