SpringApplication.run執行流程
1.這個方法裡面首先建立一個SpringApplication物件例項,然後呼叫這個建立好的SpringApplication的例項方法。在SpringApplication例項初始化的時候,它會提前做幾件事情:
@SuppressWarnings({ "unchecked", "rawtypes" }) public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); //把sources設定到SpringApplication的sources屬性中 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = deduceWebApplicationType(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
(1)根據classpath裡面是否存在某個特徵類來決定web應用型別,這個型別會用來建立相應的ApplicationContext
(2)使用SpringFactoriesLoader在應用的classpath中查詢並載入所有可用的ApplicationContextInitializer.
(3)使用SpringFactoriesLoader在應用的classpath中查詢並載入所有可用的ApplicationListener.
(4)推斷並設定main方法的定義類。
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); 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); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
2. SpringApplication例項初始化完成並且完成設定後,就開始執行run方法的邏輯了,首先遍歷所有通過SpringFactoriesLoader載入的SpringApplicationRunListener,呼叫它們的started方法。
3. 建立並配置當前Spring Boot應用將要使用的Environment
4. 遍歷呼叫所有SpringApplicationRunListener的environmentPrepared()的方法
5. 如果SpringApplication的showBanner屬性被設定為true,則列印banner
6. 根據使用者是否明確設定了applicationContextClass型別以及初始化階段的推斷結果,決定該為當前SpringBoot應用建立什麼型別的ApplicationContext,然後根據條件決定是否新增ShutdownHook,決定是否使用自定義的BeanNameGenerator,決定是否使用自定義的ResourceLoader,最重要的,是將之前準備好的Environment設定給建立好的ApplicationContext使用。
7. ApplicationContext建立好之後,SpringApplication會再次藉助Spring-FactoriesLoader,查詢並載入classpath中所有可用的ApplicatinContext-Initializer,然後遍歷呼叫這些ApplicationContextInitializer的initialize(applicationContext)方法對已經建立好的ApplicationContext進行進一步的處理。
8.遍歷呼叫所有SpringApplicationRunListener的contextPrepared()方法。
9. 最核心的一步,將之前通過@EnableAutoConfiguration獲取的所有配置以及其他形式的IoC容器配置載入到已經準備完畢的ApplicationContext。
10. 遍歷呼叫所有SpringApplicationRunListener的contextLoaded()方法。
11.呼叫ApplicationContext的refresh()方法,完成IoC容器可用的最後上道工序。
12. 查詢當前ApplicationContext中是否註冊有CommandLineRunner,如果有,則遍歷執行它們。
13. 正常情況下,遍歷執行SpringApplicationRunListener的方法表示啟動完成(如果整個過程出現異常,會把異常資訊也傳給listener)
最後歡迎大家訪問我的個人網站:1024s