天天看點

SpringBoot2.0之SpringApplication源碼分析

此源碼分析針對于SpringBoot的2.0.1.RELEASE版本

一、首先我們先看到啟動類中
SpringBoot2.0之SpringApplication源碼分析
二、點選進入SpringApplication的run方法
SpringBoot2.0之SpringApplication源碼分析

由此可以看出SpringApplication.run(AppWeiXin.class, args);實際上是傳回的有對象的。即ConfigurableApplicationContext

三、繼續進入run方法
SpringBoot2.0之SpringApplication源碼分析

由此我們可以知道

ConfigurableApplicationContext run = SpringApplication.run(AppWeiXin.class, args);
//其實就等于
ConfigurableApplicationContext run = new SpringApplication(AppWeiXin.class).run(args);
           
四、繼續進入SpringApplication
SpringBoot2.0之SpringApplication源碼分析

可以知道,SpringApplication的有參構造方法再次調用了它的重載有參構造方法

五、然後我們看到上面大紅框中的this.webApplicationType = deduceWebApplicationType();,進入deduceWebApplicationType方法
SpringBoot2.0之SpringApplication源碼分析

點選進入ClassUtil.isPresent方法中,同時進入REACTIVE_WEB_ENVIRONMENT_CLASS等幾個常量中,我們可以知道deduceWebApplicationType就是判斷是否為web應用,通過classLoader判斷是否加載的有以下三個類

public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
			+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

	private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
			+ "web.reactive.DispatcherHandler";

	private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
			+ "web.servlet.DispatcherServlet";
           

然後我進入WebApplicationType中,看到NONE,SERVLET,REACTIVE三種枚舉常量,檢視官方文檔官方文檔可知:

SpringBoot2.0之SpringApplication源碼分析
六、看到四中的setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));

我們可以先看(Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class),它其實就是從類路徑下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然後再将其儲存到List<ApplicationListener<?>>中

SpringBoot2.0之SpringApplication源碼分析
SpringBoot2.0之SpringApplication源碼分析
SpringBoot2.0之SpringApplication源碼分析
SpringBoot2.0之SpringApplication源碼分析
七、看到四中的setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));,原理同六

它是從類路徑下找到META-INF/spring.factories配置的所有ApplicationListener

八、然後擷取Main函數主類
九、SpringBoot的run方法說明
public ConfigurableApplicationContext run(String... args) {
 // 構造一個任務執行觀察器
   StopWatch stopWatch = new StopWatch();
// 開始執行,記錄開始時間
   stopWatch.start();
// 聲明IOC容器
   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   configureHeadlessProperty();
// 擷取SpringApplicationRunListeners,内部隻有一個EventPublishingRunListener
   SpringApplicationRunListeners listeners = getRunListeners(args);
    //回調所有的擷取SpringApplicationRunListener.starting()方法
 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, listeners, exceptionReporters, ex);
      throw new IllegalStateException(ex);
   }
   listeners.running(context);
   return context;
}