Spring Boot能夠輕鬆建立獨立的,生產級的基於Spring的應用程序,而這隻須要不多的一些Spring配置。本文將從SpringBoot的啓動流程角度簡要的分析SpringBoot啓動過程當中主要作了哪些事情。java
說明: springboot 2.0.6.RELEASEweb
附原始大圖連接redis
啓動流程從角度來看,主要分兩個步驟。第一個步驟是構造一個SpringApplication應用,第二個步驟是調用它的run方法,啓動應用。spring
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
可對照文章頂部的流程圖和源碼分析函數
/**建立並刷新應用上下文**/ 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
文件獲取各類各樣的工廠接口的實現類,經過反射獲取這些類的類對象、構造方法,最終生成實例。
備註:下一篇將經過spring-boot-starter-data-redis
來分析SpringBoot對redis的自動化配置是如何操做的,以及SpringFactoriesLoader在SpringApplication啓動過程當中的各個階段時發揮了什麼做用?