springboot啟動(dòng)(2) -- 啟動(dòng)流程

根據(jù)springboot啟動(dòng)(1)的分析,springboot真正啟動(dòng)從應(yīng)用主類main方法開始,其run方法中由SpringApplication完成真正啟動(dòng)。

  1. new 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 = Collections.emptySet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }
  • 配置是否為web應(yīng)用的lambda方法(默認(rèn)web應(yīng)用)
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
  • 創(chuàng)建應(yīng)用上下文工廠,用于自動(dòng)裝配等(默認(rèn)SERVLET,及支持注解的servlet)
@FunctionalInterface
public interface ApplicationContextFactory {
    ApplicationContextFactory DEFAULT = (webApplicationType) -> {
        try {
            switch(webApplicationType) {
            case SERVLET:
                return new AnnotationConfigServletWebServerApplicationContext();
            case REACTIVE:
                return new AnnotationConfigReactiveWebServerApplicationContext();
            default:
                return new AnnotationConfigApplicationContext();
            }
        } catch (Exception var2) {
            throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
        }
    };
  • 讀取spring.factories文件獲取監(jiān)聽配置并創(chuàng)建監(jiān)聽器
  • 配置應(yīng)用啟動(dòng)類
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
  1. SpringApplication.run
public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
  • 監(jiān)聽器發(fā)布應(yīng)用開始啟動(dòng)
  • 獲取應(yīng)用配置:ConfigurableEnvironment(包含logger、應(yīng)用環(huán)境、應(yīng)用參數(shù)等)
  • 創(chuàng)建應(yīng)用上下文:createApplicationContext
    默認(rèn)AnnotationConfigServletWebServerApplicationContext,讀取配置環(huán)境、加載監(jiān)聽,構(gòu)造資源加載器reader、pacakge scanner,構(gòu)造bean工廠加載器。
  • 啟動(dòng)前準(zhǔn)備工作:prepareContext
    通過bean工廠生產(chǎn)所需bean,配置各類資源
  • 刷新上下文:refreshContext
    自動(dòng)裝配springboot配置組件(如mybatis等),創(chuàng)建web server(如tomcat)。
  • 再刷新上下文(空實(shí)現(xiàn)留作擴(kuò)展)
  • 發(fā)布啟動(dòng)完成事件
  1. 自動(dòng)裝配
    自動(dòng)裝配在AbstractApplicationContext.refresh中完成的,由invokeBeanFactoryPostProcessors方法執(zhí)行自動(dòng)裝配鏈條。
  • 獲取bean工廠加載器、資源加載器
  • 資源加載器讀取spring.factories配置文件,獲取待加載bean及其全路徑
  • 通過反射獲取待加載bean的class對象和構(gòu)造方法
  • 實(shí)例化所有待加載bean,并加入spring容器

上述3個(gè)步驟就是springboot啟動(dòng)大致流程,前期主要完成配置環(huán)境讀取、加載監(jiān)聽器、構(gòu)造工廠加載器合和資源加載器。其中核心是在刷新上下文refreshContext,包含了web server的啟動(dòng)和自動(dòng)裝備。

自動(dòng)裝配流程:

  • @EnableAutoConfiguration模塊的
    通過自定義@Enable模塊驅(qū)動(dòng)測試知道,springboot通過@ImportSelector等注解類,實(shí)現(xiàn)bean的實(shí)例化和注入。@EnableAutoConfiguration同樣的實(shí)現(xiàn)原理,其ImportSelector接口方法實(shí)現(xiàn)中會(huì)掃描項(xiàng)目下的spring.factories,獲取待加載類。
  • 讀取各jar包下spring.factories文件的配置內(nèi)容,該文件結(jié)構(gòu)為:接口=接口實(shí)現(xiàn)類列表,比如mongodb的jar包下
org.springframework.data.web.config.SpringDataJacksonModules=org.springframework.data.mongodb.config.GeoJsonConfiguration
org.springframework.data.repository.core.support.RepositoryFactorySupport=org.springframework.data.mongodb.repository.support.MongoRepositoryFactory
  • @EnableAutoConfiguration模塊獲取到類后,通過工廠反射實(shí)例化待加載類。

在springboot的各功能模塊spring.factories文件中配置了大量默認(rèn)實(shí)現(xiàn)接口。再加上springboot的條件裝配,通過配置文件實(shí)現(xiàn)配置的功能模塊。比如,springboot中包含了mongodb的實(shí)現(xiàn)MongoTemplate,只需要在配置文件中添加mongodb的依賴,就能在自動(dòng)裝配接的完成mongodb服務(wù)MongoTemplate的加載。

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

springboot這種帶有默認(rèn)實(shí)現(xiàn)的配置方式,體現(xiàn)了其“規(guī)約大于配置”的思想,用戶開箱即用,極大提高了開發(fā)效率。

參考:https://www.cnblogs.com/trgl/p/7353782.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容