更新時間:2023-08-11 來源:黑馬程序員 瀏覽量:
SpringApplication實例的初始化
查看SpringApplication實例對象初始化的源碼信息,核心代碼如下。
public SpringApplication (Resourceloader resourceLoader, Class... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook ? true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceloader;
Assert.notNull (primarySources, "PrimarySources must not be null");
this.primarySorces = new LinkedlashSep(Arrays.aslist(primarySources));
this.webApplicationType = WebApplicationType.daduceFromClasspath () ;
this.setInitializers (this.getSpringFactoriesInstances(
ApplicationContextInitializer.class)) ;
this.setListeners (this.getSpringFactoriesInstances (ApplicationIistener.class)) ;
this.mainApplicationClass = this.deduceMainApplicationClass ();
}
從上述源碼可以看出,SpringApplication的初始化過程主要包括4部分,具體說明如下。(1) this.webApplicationType = WebApplicationType.deduceFromClasspath()
用于判斷當前 webApplicationType 應用的類型。deduceFromClasspath()方法用于查看Classpath 類路徑下是否存在某個特征類,從而判斷當前webApplicationType類型是SERVLET應用(Spring 5之前的傳統(tǒng)MVC應用)還是REACTIVE應用(Spring 5開始出現(xiàn)的WebFlux交互式應用)。
(2 ) this.setlnitializers(this.getSpringFactorieslnstances(ApplicationContextlnitializer.class))
用于設置SpringApplication 應用的初始化器。在初始化器設置過程中,會使用Spring類加載器 SpringFactoriesLoader 從 META-INF/spring.factories 類路徑下的 META-INF 下的spring.factores 文件中獲取所有可用的應用初始化器類ApplicationContextlnitializer。
(3) this.setListeners(this.getSpringFactoriesinstances(ApplicationListener.class))
用于設置 SpringApplication應用的監(jiān)聽器。監(jiān)聽器設置的過程與上一步初始化器設置的過程基本一樣,也是使用SpringFactoriesLoader從 META-INF/spring.factories 類路徑下的META-INF下的spring.factores文件中獲取所有可用的監(jiān)聽器類ApplicationListener。
(4) this.mainApplicationClass = this.deduceMainApplicationClass()
用于推斷并設置項目main()方法啟動的主程序啟動類。
項目的初始化啟動
分析完(new SpringApplication(primarySources)).run(args)源碼前一部分 SpringApplication實例對象的初始化后,查看run(args)方法執(zhí)行的項目初始化啟動過程,核心代碼如下。
public ConfigurableApplicationContext run(String... args) {
StopNatch stopWatch = new StopNatch();
stopMatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList ();
this.configureHeadlessProperty();
// (1) 獲取SpringApplicat ion 初始化的 SpringApplicationRunListener 運行監(jiān)聽器井運行
SpringApplicationRunListeners listeners = this. getRunListeners (args) ;
listeners.starting() ;
Collection exceptionReporters;
try {
ApplicationArgunents applicationArguments =
new DefaultApplicationArguments (args);
//(2)項目運行環(huán)境Environment的頂配置
ConfigurableEnvironment environment =
this.prepareEnvirorment(listeners, applicationArgunents) ;
this.configureIgnoreBeanInfo (environment) ;
Banner printedBanner = this.printBanner (environment);
//(3)項目應用上下文Applicat ionContext 的預配置
context = this.createApplicationContext();
exceptionReporters =
this.getSpringF'actoriesInstances(SpringBootExoeptionReporter.class,
new Class [] {ConfigurableApplicationContext.class), new Cbject[] {context}) ;
this.prepareContext (context, environment, listeners,
applicationArguments, printedBanner) ;
this.refreshContext(context) ;
this.afterRefresh (context, applicationArguments);
stopNatch.stop();
if(this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass))
.logStarted(this.getApplicationLog(), stoplatch);
}
//(4)由項目運行監(jiān)聽器啟動配置好的應用上下文ApplicationContext
listeners.started(context);
//(5)調(diào)用應用上下文ApplicationContext中配置的程序執(zhí)行器XxxRunner
this.callRunners (context, applicationArguments) ;
} catch (Throwable var10) {
this.handleRunFailure (context, var10, exceptionReporters, listeners};
throw new IllegalStateException(var10);
}
try {
//(6)由項目運行監(jiān)聽器持續(xù)運行配置好的應用上下文ApplicationContext
listeners")rs.running (context);
return context;
} catch (Throwable var9) {
this.handleRunFailure (context, var9, exceptionReporters,
(SpringApplicationRunListeners) null);
throw new IllegalStateException(var9);
}
}
從上述源碼可以看出,項目初始化啟動過程大致包括以下6部分。
(1)this.getRunListeners(args)和listeners.starting()方法主要用于獲取 SpringApplication實例初始化過程中初始化的SpringApplicationRunListener 監(jiān)聽器并運行。
(2)this.prepareEnvironment(listeners,applicationArguments)方法主要用于對項目運行環(huán)境進行預設置,同時通過 this.configurelgnoreBeanlnfo(environment)方法排除一些不需要的運行環(huán)境。
(3)this.createApplicationContext()方法及下面加粗部分代碼,主要作用是對項目應用上下文ApplicationContext的預配置,包括先創(chuàng)建應用上下文環(huán)境ApplicationContext,接著使用之前初始化設置的context(應用上下文環(huán)境)、environment(項目運行環(huán)境)、listeners(運行監(jiān)聽器)、applicationArguments(項目參數(shù))和 printedBanner(項目圖標信息)進行應用上下文的組裝配置,并刷新配置。
(4)listeners.started(context)方法用于使運行監(jiān)聽器SpringApplicationRunListener啟動配置好的應用上下文 ApplicationContext。
(5)this.callRunners(context,applicationArguments)方法用于調(diào)用項自中自定義的執(zhí)行器XxxRunner類,使得在項目啟動完成后立即執(zhí)行一些特定程序。其中,Spring Boot提供的執(zhí)行器接口有ApplicationRunner 和 CommandLineRunner 兩種,在使用時只需要自定義一個執(zhí)行器類實現(xiàn)其中一個按]并重寫對應的run()方法接口,Spring Boot 項目啟動后即會立即執(zhí)行這些特定程序。
(6) listeners.running(context)方法表示在前面一切初始化啟動都沒有問題的情況下,使用運行監(jiān)聽器SpringApplicationRunListener 持續(xù)運行配置好的應用上下文ApplicationContext,這樣整個Spring Boot 項目就正式啟動完成了。與此同時,經(jīng)過初始化封裝設置的應用上下文
ApplicationContext也處于活躍狀態(tài)。
至此,關(guān)于Spring Boot執(zhí)行流程中項目的初始化啟動已經(jīng)分析完畢。經(jīng)過上面對項目啟動過程中兩階段源碼的詳細分析,相信大家對Spring Boot 執(zhí)行流程已經(jīng)有了大體的認識,雖然大部分內(nèi)容都較為復雜,但在學習過程中只要了解源碼中部分重要內(nèi)容即可。
下面我們通過一個Spring Boot 執(zhí)行流程圖,來讓大家更清晰地知道 Spring Boot的整體執(zhí)行流程和主要啟動階段,具體如所示。