首頁(yè)常見(jiàn)問(wèn)題正文

SpringApplication實(shí)例的初始化和項(xiàng)目初始化啟動(dòng)

更新時(shí)間:2023-08-11 來(lái)源:黑馬程序員 瀏覽量:

SpringApplication實(shí)例的初始化

查看SpringApplication實(shí)例對(duì)象初始化的源碼信息,核心代碼如下。

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的初始化過(guò)程主要包括4部分,具體說(shuō)明如下。

(1) this.webApplicationType = WebApplicationType.deduceFromClasspath()

用于判斷當(dāng)前 webApplicationType 應(yīng)用的類(lèi)型。deduceFromClasspath()方法用于查看Classpath 類(lèi)路徑下是否存在某個(gè)特征類(lèi),從而判斷當(dāng)前webApplicationType類(lèi)型是SERVLET應(yīng)用(Spring 5之前的傳統(tǒng)MVC應(yīng)用)還是REACTIVE應(yīng)用(Spring 5開(kāi)始出現(xiàn)的WebFlux交互式應(yīng)用)。

(2 ) this.setlnitializers(this.getSpringFactorieslnstances(ApplicationContextlnitializer.class))

用于設(shè)置SpringApplication 應(yīng)用的初始化器。在初始化器設(shè)置過(guò)程中,會(huì)使用Spring類(lèi)加載器 SpringFactoriesLoader 從 META-INF/spring.factories 類(lèi)路徑下的 META-INF 下的spring.factores 文件中獲取所有可用的應(yīng)用初始化器類(lèi)ApplicationContextlnitializer。

(3) this.setListeners(this.getSpringFactoriesinstances(ApplicationListener.class))

用于設(shè)置 SpringApplication應(yīng)用的監(jiān)聽(tīng)器。監(jiān)聽(tīng)器設(shè)置的過(guò)程與上一步初始化器設(shè)置的過(guò)程基本一樣,也是使用SpringFactoriesLoader從 META-INF/spring.factories 類(lèi)路徑下的META-INF下的spring.factores文件中獲取所有可用的監(jiān)聽(tīng)器類(lèi)ApplicationListener。

(4) this.mainApplicationClass = this.deduceMainApplicationClass()

用于推斷并設(shè)置項(xiàng)目main()方法啟動(dòng)的主程序啟動(dòng)類(lèi)。

項(xiàng)目的初始化啟動(dòng)

分析完(new SpringApplication(primarySources)).run(args)源碼前一部分 SpringApplication實(shí)例對(duì)象的初始化后,查看run(args)方法執(zhí)行的項(xiàng)目初始化啟動(dòng)過(guò)程,核心代碼如下。

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 運(yùn)行監(jiān)聽(tīng)器井運(yùn)行
    SpringApplicationRunListeners listeners = this. getRunListeners (args) ;
    listeners.starting() ;
    Collection exceptionReporters;
    try {
        ApplicationArgunents applicationArguments =
                    new DefaultApplicationArguments (args);
        //(2)項(xiàng)目運(yùn)行環(huán)境Environment的頂配置
        ConfigurableEnvironment environment =
                        this.prepareEnvirorment(listeners, applicationArgunents) ;
        this.configureIgnoreBeanInfo (environment) ;
        Banner printedBanner = this.printBanner (environment);
        //(3)項(xiàng)目應(yīng)用上下文Applicat ionContext 的預(yù)配置
        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)由項(xiàng)目運(yùn)行監(jiān)聽(tīng)器啟動(dòng)配置好的應(yīng)用上下文ApplicationContext
        listeners.started(context);
        //(5)調(diào)用應(yīng)用上下文ApplicationContext中配置的程序執(zhí)行器XxxRunner
        this.callRunners (context, applicationArguments) ;
    } catch (Throwable var10) {
        this.handleRunFailure (context, var10, exceptionReporters, listeners};
        throw new IllegalStateException(var10);
    }
    try {
        //(6)由項(xiàng)目運(yùn)行監(jiān)聽(tīng)器持續(xù)運(yùn)行配置好的應(yīng)用上下文ApplicationContext
        listeners")rs.running (context);
        return context;
    } catch (Throwable var9) {
    this.handleRunFailure (context, var9, exceptionReporters,
                                (SpringApplicationRunListeners) null);
    throw new IllegalStateException(var9);
    }
}

從上述源碼可以看出,項(xiàng)目初始化啟動(dòng)過(guò)程大致包括以下6部分。

(1)this.getRunListeners(args)和listeners.starting()方法主要用于獲取 SpringApplication實(shí)例初始化過(guò)程中初始化的SpringApplicationRunListener 監(jiān)聽(tīng)器并運(yùn)行。

(2)this.prepareEnvironment(listeners,applicationArguments)方法主要用于對(duì)項(xiàng)目運(yùn)行環(huán)境進(jìn)行預(yù)設(shè)置,同時(shí)通過(guò) this.configurelgnoreBeanlnfo(environment)方法排除一些不需要的運(yùn)行環(huán)境。

(3)this.createApplicationContext()方法及下面加粗部分代碼,主要作用是對(duì)項(xiàng)目應(yīng)用上下文ApplicationContext的預(yù)配置,包括先創(chuàng)建應(yīng)用上下文環(huán)境ApplicationContext,接著使用之前初始化設(shè)置的context(應(yīng)用上下文環(huán)境)、environment(項(xiàng)目運(yùn)行環(huán)境)、listeners(運(yùn)行監(jiān)聽(tīng)器)、applicationArguments(項(xiàng)目參數(shù))和 printedBanner(項(xiàng)目圖標(biāo)信息)進(jìn)行應(yīng)用上下文的組裝配置,并刷新配置。

(4)listeners.started(context)方法用于使運(yùn)行監(jiān)聽(tīng)器SpringApplicationRunListener啟動(dòng)配置好的應(yīng)用上下文 ApplicationContext。

(5)this.callRunners(context,applicationArguments)方法用于調(diào)用項(xiàng)自中自定義的執(zhí)行器XxxRunner類(lèi),使得在項(xiàng)目啟動(dòng)完成后立即執(zhí)行一些特定程序。其中,Spring Boot提供的執(zhí)行器接口有ApplicationRunner 和 CommandLineRunner 兩種,在使用時(shí)只需要自定義一個(gè)執(zhí)行器類(lèi)實(shí)現(xiàn)其中一個(gè)按]并重寫(xiě)對(duì)應(yīng)的run()方法接口,Spring Boot 項(xiàng)目啟動(dòng)后即會(huì)立即執(zhí)行這些特定程序。

(6) listeners.running(context)方法表示在前面一切初始化啟動(dòng)都沒(méi)有問(wèn)題的情況下,使用運(yùn)行監(jiān)聽(tīng)器SpringApplicationRunListener 持續(xù)運(yùn)行配置好的應(yīng)用上下文ApplicationContext,這樣整個(gè)Spring Boot 項(xiàng)目就正式啟動(dòng)完成了。與此同時(shí),經(jīng)過(guò)初始化封裝設(shè)置的應(yīng)用上下文

ApplicationContext也處于活躍狀態(tài)。

至此,關(guān)于Spring Boot執(zhí)行流程中項(xiàng)目的初始化啟動(dòng)已經(jīng)分析完畢。經(jīng)過(guò)上面對(duì)項(xiàng)目啟動(dòng)過(guò)程中兩階段源碼的詳細(xì)分析,相信大家對(duì)Spring Boot 執(zhí)行流程已經(jīng)有了大體的認(rèn)識(shí),雖然大部分內(nèi)容都較為復(fù)雜,但在學(xué)習(xí)過(guò)程中只要了解源碼中部分重要內(nèi)容即可。

下面我們通過(guò)一個(gè)Spring Boot 執(zhí)行流程圖,來(lái)讓大家更清晰地知道 Spring Boot的整體執(zhí)行流程和主要啟動(dòng)階段,具體如所示。
Spring Boot的整體執(zhí)行流程

分享到:
在線咨詢 我要報(bào)名
和我們?cè)诰€交談!