欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Boot從main方法到內(nèi)嵌Tomcat的全過(guò)程(自動(dòng)化流程)

 更新時(shí)間:2025年07月22日 11:40:53   作者:程序員Meteor  
SpringBoot啟動(dòng)始于main方法,創(chuàng)建SpringApplication實(shí)例,初始化上下文,準(zhǔn)備環(huán)境,刷新容器并啟動(dòng)內(nèi)嵌Tomcat,通過(guò)自動(dòng)配置加載必要類(lèi)完成應(yīng)用部署,本文給大家介紹Spring Boot從main方法到內(nèi)嵌Tomcat的全過(guò)程,感興趣的朋友一起看看吧

Spring Boot的啟動(dòng)過(guò)程是一個(gè)精心設(shè)計(jì)的自動(dòng)化流程,下面我將詳細(xì)闡述從main方法開(kāi)始到內(nèi)嵌Tomcat啟動(dòng)的全過(guò)程。

1. 入口:main方法

一切始于一個(gè)簡(jiǎn)單的main方法:

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

2. SpringApplication初始化

SpringApplication.run()方法內(nèi)部會(huì)創(chuàng)建一個(gè)SpringApplication實(shí)例:

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return new SpringApplication(primarySource).run(args);
}

2.1 構(gòu)造階段

在SpringApplication構(gòu)造函數(shù)中完成以下關(guān)鍵操作:

  • 推斷應(yīng)用類(lèi)型:判斷是Servlet應(yīng)用(Spring MVC)還是Reactive應(yīng)用(Spring WebFlux)
  • 加載ApplicationContextInitializer:通過(guò)META-INF/spring.factories加載
  • 加載ApplicationListener:同樣通過(guò)spring.factories機(jī)制加載
  • 推斷主配置類(lèi):通過(guò)堆棧分析找到包含main方法的類(lèi)

3. 運(yùn)行階段:run()方法

run()方法是整個(gè)啟動(dòng)過(guò)程的核心:

public ConfigurableApplicationContext run(String... args) {
    // 1. 創(chuàng)建并啟動(dòng)計(jì)時(shí)器
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    // 2. 初始化應(yīng)用上下文和異常報(bào)告器
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    // 3. 獲取SpringApplicationRunListeners并啟動(dòng)
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    try {
        // 4. 準(zhǔn)備環(huán)境
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        // 5. 打印Banner
        Banner printedBanner = printBanner(environment);
        // 6. 創(chuàng)建應(yīng)用上下文
        context = createApplicationContext();
        // 7. 準(zhǔn)備應(yīng)用上下文
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 8. 刷新應(yīng)用上下文(關(guān)鍵步驟)
        refreshContext(context);
        // 9. 刷新后處理
        afterRefresh(context, applicationArguments);
        // 10. 停止計(jì)時(shí)器并發(fā)布啟動(dòng)完成事件
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                .logStarted(getApplicationLog(), stopWatch);
        }
        listeners.started(context);
        // 11. 執(zhí)行Runner
        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;
}

4. 創(chuàng)建應(yīng)用上下文

createApplicationContext()方法根據(jù)應(yīng)用類(lèi)型創(chuàng)建不同的應(yīng)用上下文:

  • Servlet環(huán)境:創(chuàng)建AnnotationConfigServletWebServerApplicationContext
  • Reactive環(huán)境:創(chuàng)建AnnotationConfigReactiveWebServerApplicationContext
  • 普通環(huán)境:創(chuàng)建AnnotationConfigApplicationContext

對(duì)于Web應(yīng)用,會(huì)創(chuàng)建AnnotationConfigServletWebServerApplicationContext,它繼承自ServletWebServerApplicationContext。

5. 準(zhǔn)備應(yīng)用上下文

prepareContext()方法完成以下工作:

  • 將環(huán)境綁定到上下文
  • 后置處理上下文
  • 應(yīng)用所有初始化器
  • 發(fā)布ContextPrepared事件
  • 注冊(cè)主配置類(lèi)bean定義
  • 發(fā)布ContextLoaded事件

6. 刷新應(yīng)用上下文

refreshContext()最終調(diào)用AbstractApplicationContext.refresh(),這是Spring容器的核心刷新流程:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 準(zhǔn)備刷新
        prepareRefresh();
        // 2. 獲取新的BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // 3. 準(zhǔn)備BeanFactory
        prepareBeanFactory(beanFactory);
        try {
            // 4. 后置處理BeanFactory
            postProcessBeanFactory(beanFactory);
            // 5. 調(diào)用BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);
            // 6. 注冊(cè)BeanPostProcessor
            registerBeanPostProcessors(beanFactory);
            // 7. 初始化MessageSource
            initMessageSource();
            // 8. 初始化事件廣播器
            initApplicationEventMulticaster();
            // 9. 初始化特殊bean(由子類(lèi)實(shí)現(xiàn))
            onRefresh();
            // 10. 注冊(cè)監(jiān)聽(tīng)器
            registerListeners();
            // 11. 初始化所有非懶加載單例
            finishBeanFactoryInitialization(beanFactory);
            // 12. 完成刷新
            finishRefresh();
        }
        catch (BeansException ex) {
            // 處理異常...
        }
    }
}

7. 內(nèi)嵌Tomcat啟動(dòng)的關(guān)鍵:onRefresh()

對(duì)于Servlet Web應(yīng)用,ServletWebServerApplicationContext重寫(xiě)了onRefresh()方法:

protected void onRefresh() {
    super.onRefresh();
    try {
        createWebServer();
    }
    catch (Throwable ex) {
        throw new ApplicationContextException("Unable to start web server", ex);
    }
}

createWebServer()是內(nèi)嵌服務(wù)器啟動(dòng)的關(guān)鍵:

private void createWebServer() {
    WebServer webServer = this.webServer;
    ServletContext servletContext = getServletContext();
    if (webServer == null && servletContext == null) {
        // 1. 獲取WebServer工廠(chǎng)(Tomcat, Jetty或Undertow)
        ServletWebServerFactory factory = getWebServerFactory();
        // 2. 創(chuàng)建WebServer
        this.webServer = factory.getWebServer(getSelfInitializer());
    }
    else if (servletContext != null) {
        try {
            getSelfInitializer().onStartup(servletContext);
        }
        catch (ServletException ex) {
            throw new ApplicationContextException("Cannot initialize servlet context", ex);
        }
    }
    initPropertySources();
}

8. Tomcat服務(wù)器創(chuàng)建過(guò)程

以Tomcat為例,TomcatServletWebServerFactory.getWebServer()方法:

public WebServer getWebServer(ServletContextInitializer... initializers) {
    // 1. 創(chuàng)建Tomcat實(shí)例
    Tomcat tomcat = new Tomcat();
    // 2. 配置基礎(chǔ)目錄
    File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    // 3. 配置連接器
    Connector connector = new Connector(this.protocol);
    connector.setThrowOnFailure(true);
    tomcat.getService().addConnector(connector);
    customizeConnector(connector);
    tomcat.setConnector(connector);
    // 4. 配置Host
    tomcat.getHost().setAutoDeploy(false);
    configureEngine(tomcat.getEngine());
    // 5. 準(zhǔn)備上下文
    prepareContext(tomcat.getHost(), initializers);
    // 6. 創(chuàng)建TomcatWebServer并啟動(dòng)
    return getTomcatWebServer(tomcat);
}

9. 啟動(dòng)Tomcat

TomcatWebServer構(gòu)造函數(shù)中完成Tomcat的啟動(dòng):

public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
    this.tomcat = tomcat;
    this.autoStart = autoStart;
    initialize();
}
private void initialize() throws WebServerException {
    // 啟動(dòng)Tomcat
    this.tomcat.start();
    // 啟動(dòng)一個(gè)守護(hù)線(xiàn)程來(lái)等待停止命令
    startDaemonAwaitThread();
}

10. 自動(dòng)配置的關(guān)鍵

整個(gè)過(guò)程中,自動(dòng)配置是通過(guò)@SpringBootApplication注解中的@EnableAutoConfiguration實(shí)現(xiàn)的:

  • invokeBeanFactoryPostProcessors()階段會(huì)處理自動(dòng)配置
  • AutoConfigurationImportSelector會(huì)加載META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中的配置類(lèi)
  • 對(duì)于Tomcat,會(huì)加載ServletWebServerFactoryAutoConfiguration
  • 這個(gè)配置類(lèi)通過(guò)@Import引入了EmbeddedTomcat等配置

總結(jié)流程

  1. 啟動(dòng)main方法
  2. 創(chuàng)建SpringApplication實(shí)例
  3. 運(yùn)行run()方法
  4. 準(zhǔn)備環(huán)境
  5. 創(chuàng)建應(yīng)用上下文(AnnotationConfigServletWebServerApplicationContext)
  6. 準(zhǔn)備上下文(注冊(cè)配置類(lèi)等)
  7. 刷新上下文(核心)
    • 調(diào)用onRefresh()
    • 創(chuàng)建內(nèi)嵌Web服務(wù)器(Tomcat)
    • 啟動(dòng)Tomcat
  8. 發(fā)布啟動(dòng)完成事件
  9. 執(zhí)行Runner

到此這篇關(guān)于Spring Boot從main方法到內(nèi)嵌Tomcat的全過(guò)程(自動(dòng)化流程)的文章就介紹到這了,更多相關(guān)Spring Boot啟動(dòng)過(guò)程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java服務(wù)假死之生產(chǎn)事故的排查與優(yōu)化問(wèn)題

    Java服務(wù)假死之生產(chǎn)事故的排查與優(yōu)化問(wèn)題

    在服務(wù)器上通過(guò)curl命令調(diào)用一個(gè)Java服務(wù)的查詢(xún)接口,半天沒(méi)有任何響應(yīng),怎么進(jìn)行這一現(xiàn)象排查呢,下面小編給大家記一次生產(chǎn)事故的排查與優(yōu)化——Java服務(wù)假死問(wèn)題,感興趣的朋友一起看看吧
    2022-07-07
  • 如何解決java.net.BindException:地址已在使用問(wèn)題

    如何解決java.net.BindException:地址已在使用問(wèn)題

    當(dāng)Zookeeper啟動(dòng)報(bào)錯(cuò)“java.net.BindException:地址已在使用”時(shí),通常是因?yàn)橹付ǖ亩丝谝驯黄渌M(jìn)程占用,解決這個(gè)問(wèn)題需要按照以下步驟操作:首先,使用命令如lsof -i:2181找到占用該端口的進(jìn)程號(hào);其次,使用kill命令終止該進(jìn)程
    2024-09-09
  • java如何多線(xiàn)程批量更新10萬(wàn)級(jí)的數(shù)據(jù)

    java如何多線(xiàn)程批量更新10萬(wàn)級(jí)的數(shù)據(jù)

    在處理大數(shù)據(jù)量的批量更新時(shí),直接使用mybatis的updateBatch可能導(dǎo)致效率低下甚至OOM,通過(guò)每次處理5000條數(shù)據(jù)的方式雖然安全但效率低,更優(yōu)的解決方案是使用多線(xiàn)程處理,將數(shù)據(jù)分批并多線(xiàn)程執(zhí)行,有效提高了處理速度并保證了系統(tǒng)穩(wěn)定性
    2024-10-10
  • Java的Flowable工作流之加簽轉(zhuǎn)簽詳解

    Java的Flowable工作流之加簽轉(zhuǎn)簽詳解

    這篇文章主要介紹了Java的Flowable工作流之加簽轉(zhuǎn)簽詳解,Flowable是一個(gè)開(kāi)源的工作流引擎,它提供了一套強(qiáng)大的工具和功能,用于設(shè)計(jì)、執(zhí)行和管理各種類(lèi)型的工作流程,需要的朋友可以參考下
    2023-11-11
  • IDEA下創(chuàng)建SpringBoot+MyBatis+MySql項(xiàng)目實(shí)現(xiàn)動(dòng)態(tài)登錄與注冊(cè)功能

    IDEA下創(chuàng)建SpringBoot+MyBatis+MySql項(xiàng)目實(shí)現(xiàn)動(dòng)態(tài)登錄與注冊(cè)功能

    這篇文章主要介紹了IDEA下創(chuàng)建SpringBoot+MyBatis+MySql項(xiàng)目實(shí)現(xiàn)動(dòng)態(tài)登錄與注冊(cè)功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • Java連接Hbase的項(xiàng)目實(shí)踐

    Java連接Hbase的項(xiàng)目實(shí)踐

    HBase是基于Hadoop的高可靠、高性能、面向列的NoSQL數(shù)據(jù)庫(kù),它提供了對(duì)海量數(shù)據(jù)的存儲(chǔ)和實(shí)時(shí)讀寫(xiě)的能力,本文主要介紹了Java連接Hbase的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • spring/springboot整合dubbo詳細(xì)教程

    spring/springboot整合dubbo詳細(xì)教程

    今天教大家如何使用spring/springboot整合dubbo,文中有非常詳細(xì)的圖文介紹及代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • java實(shí)現(xiàn)圖書(shū)檢索系統(tǒng)

    java實(shí)現(xiàn)圖書(shū)檢索系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)圖書(shū)檢索系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • java線(xiàn)程池工作隊(duì)列飽和策略代碼示例

    java線(xiàn)程池工作隊(duì)列飽和策略代碼示例

    這篇文章主要介紹了java線(xiàn)程池工作隊(duì)列飽和策略代碼示例,涉及線(xiàn)程池的簡(jiǎn)單介紹,工作隊(duì)列飽和策略的分析及代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • 淺談常用Java數(shù)據(jù)庫(kù)連接池(小結(jié))

    淺談常用Java數(shù)據(jù)庫(kù)連接池(小結(jié))

    這篇文章主要介紹了淺談常用Java數(shù)據(jù)庫(kù)連接池(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07

最新評(píng)論