最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot通過main方法啟動web項目實踐

 更新時間:2025年08月18日 14:15:12   作者:dj_master  
SpringBoot通過SpringApplication.run()啟動Web項目,自動推斷應(yīng)用類型,加載初始化器與監(jiān)聽器,配置SpringMVC組件,啟動嵌入式服務(wù)器,實現(xiàn)零配置啟動

Spring Boot 通過 main 方法啟動 Web 項目的過程涉及多個核心組件和自動化機制,下面從源碼角度詳細(xì)拆解:

1. 啟動入口:SpringApplication.run()

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

SpringApplication.run() 是啟動的核心入口,它主要完成以下工作:

2. SpringApplication初始化

// SpringApplication 構(gòu)造函數(shù)核心邏輯
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 1. 設(shè)置資源加載器
    this.resourceLoader = resourceLoader;
    // 2. 校驗并保存主配置類(即 @SpringBootApplication 標(biāo)注的類)
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 3. 推斷應(yīng)用類型(REACTIVE、SERVLET、NONE)
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 4. 加載并實例化 ApplicationContextInitializer
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 5. 加載并實例化 ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 6. 推斷 main 方法所在類
    this.mainApplicationClass = deduceMainApplicationClass();
}

關(guān)鍵步驟:

  • 應(yīng)用類型推斷:通過檢查類路徑中是否存在 org.springframework.web.reactive.DispatcherHandler(REACTIVE)或 javax.servlet.Servlet(SERVLET)來確定應(yīng)用類型。
  • 初始化器(Initializer):從 META-INF/spring.factories 加載 ApplicationContextInitializer,用于在 ApplicationContext 刷新前自定義配置。
  • 監(jiān)聽器(Listener):加載 ApplicationListener,監(jiān)聽啟動過程中的事件(如 ApplicationStartingEvent)。

3. run()方法核心流程

public ConfigurableApplicationContext run(String... args) {
    // 1. 計時和發(fā)布啟動事件
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    
    // 2. 獲取并啟動監(jiān)聽器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    
    try {
        // 3. 構(gòu)建應(yīng)用參數(shù)和環(huán)境配置
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        
        // 4. 創(chuàng)建并配置 ApplicationContext
        context = createApplicationContext();
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        
        // 5. 準(zhǔn)備上下文(加載 Bean 定義)
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 6. 刷新上下文(核心啟動邏輯)
        refreshContext(context);
        // 7. 刷新后的回調(diào)處理
        afterRefresh(context, applicationArguments);
        // 8. 發(fā)布應(yīng)用就緒事件
        listeners.started(context);
        // 9. 執(zhí)行 Runner(如 CommandLineRunner)
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }
    
    stopWatch.stop();
    if (this.logStartupInfo) {
        new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    }
    // 10. 發(fā)布應(yīng)用運行中事件
    listeners.running(context);
    return context;
}

4. 嵌入式 Web 服務(wù)器啟動關(guān)鍵點

4.1refreshContext()方法觸發(fā)服務(wù)器啟動

private void refreshContext(ConfigurableApplicationContext context) {
    refresh(context);
    if (this.registerShutdownHook) {
        try {
            context.registerShutdownHook();
        }
        catch (AccessControlException ex) {
            // Not allowed in some environments.
        }
    }
}

protected void refresh(ConfigurableApplicationContext context) {
    // 調(diào)用 AbstractApplicationContext 的 refresh() 方法
    context.refresh();
}

4.2ServletWebServerApplicationContext的核心作用

對于 Web 應(yīng)用,ApplicationContext 實際類型為 AnnotationConfigServletWebServerApplicationContext,它繼承自 ServletWebServerApplicationContext,后者在 refresh() 過程中會:

// ServletWebServerApplicationContext 核心方法
@Override
protected void onRefresh() {
    super.onRefresh();
    try {
        // 創(chuàng)建并啟動嵌入式 Web 服務(wù)器
        createWebServer();
    }
    catch (Throwable ex) {
        throw new ApplicationContextException("Unable to start web server", ex);
    }
}

private void createWebServer() {
    WebServer webServer = this.webServer;
    ServletContext servletContext = getServletContext();
    
    if (webServer == null && servletContext == null) {
        // 1. 獲取 ServletWebServerFactory(如 TomcatServletWebServerFactory)
        ServletWebServerFactory factory = getWebServerFactory();
        // 2. 創(chuàng)建并配置 Web 服務(wù)器
        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();
}

4.3ServletWebServerFactory實例化服務(wù)器

以 Tomcat 為例,TomcatServletWebServerFactorygetWebServer() 方法會:

@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
    // 1. 創(chuàng)建 Tomcat 實例
    Tomcat tomcat = new Tomcat();
    // 2. 配置服務(wù)器基本參數(shù)(端口、上下文路徑等)
    File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    Connector connector = new Connector(this.protocol);
    tomcat.getService().addConnector(connector);
    customizeConnector(connector);
    tomcat.setConnector(connector);
    tomcat.getHost().setAutoDeploy(false);
    // 3. 配置 ServletContextInitializer(如 DispatcherServlet)
    prepareContext(tomcat.getHost(), initializers);
    // 4. 啟動服務(wù)器
    return getTomcatWebServer(tomcat);
}

5. Spring MVC 組件自動配置

通過 WebMvcAutoConfiguration 自動配置核心組件:

  • DispatcherServlet:作為前端控制器,處理所有 HTTP 請求。
  • HandlerMapping:映射 URL 到具體的 Controller 方法。
  • ViewResolver:解析視圖名稱到實際視圖。

關(guān)鍵代碼(WebMvcAutoConfiguration):

@Bean
@Primary
@ConditionalOnMissingBean(DispatcherServlet.class)
public DispatcherServlet dispatcherServlet(WebMvcProperties properties) {
    DispatcherServlet dispatcherServlet = new DispatcherServlet();
    dispatcherServlet.setDispatchOptionsRequest(properties.isDispatchOptionsRequest());
    dispatcherServlet.setDispatchTraceRequest(properties.isDispatchTraceRequest());
    dispatcherServlet.setThrowExceptionIfNoHandlerFound(properties.isThrowExceptionIfNoHandlerFound());
    dispatcherServlet.setPublishEvents(properties.isPublishRequestHandledEvents());
    dispatcherServlet.setEnableLoggingRequestDetails(properties.isLogRequestDetails());
    return dispatcherServlet;
}

6. 最終啟動結(jié)果

  • 嵌入式服務(wù)器(如 Tomcat)啟動并監(jiān)聽指定端口(默認(rèn) 8080)。
  • DispatcherServlet 注冊到 Servlet 容器,作為所有請求的入口。
  • Spring 上下文初始化完成,所有 Bean 已加載并可用。
  • ApplicationReadyEvent 發(fā)布,標(biāo)志應(yīng)用可處理外部請求。

總結(jié):啟動流程關(guān)鍵點

  1. SpringApplication 初始化:推斷應(yīng)用類型、加載初始化器和監(jiān)聽器。
  2. 環(huán)境配置:加載 application.properties 等配置源。
  3. ApplicationContext 創(chuàng)建:根據(jù) Web 類型選擇相應(yīng)的上下文實現(xiàn)。
  4. 自動配置:基于依賴和條件注解,自動配置 Web 組件(如 DispatcherServlet)。
  5. 嵌入式服務(wù)器啟動:通過 ServletWebServerFactory 創(chuàng)建并啟動 Tomcat/Jetty。
  6. Spring MVC 初始化:配置請求映射、視圖解析等核心組件。

通過這種機制,Spring Boot 實現(xiàn)了“零配置”啟動 Web 項目的能力,開發(fā)者只需關(guān)注業(yè)務(wù)邏輯,無需手動處理服務(wù)器配置和組件裝配。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java隨機生成8位數(shù)授權(quán)碼的實例

    java隨機生成8位數(shù)授權(quán)碼的實例

    下面小編就為大家?guī)硪黄猨ava隨機生成8位數(shù)授權(quán)碼的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • SpringBoot教程_創(chuàng)建第一個SpringBoot項目

    SpringBoot教程_創(chuàng)建第一個SpringBoot項目

    這篇文章主要介紹了SpringBoot教程_創(chuàng)建第一個SpringBoot項目,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 詳解Java模擬棧的實現(xiàn)以及Stack類的介紹

    詳解Java模擬棧的實現(xiàn)以及Stack類的介紹

    棧是一種數(shù)據(jù)結(jié)構(gòu),它按照后進(jìn)先出的原則來存儲和訪問數(shù)據(jù)。Stack是一個類,表示棧數(shù)據(jù)結(jié)構(gòu)的實現(xiàn)。本文就來和大家介紹一下Java模擬棧的實現(xiàn)以及Stack類的使用,需要的可以參考一下
    2023-04-04
  • 使用FeignClient進(jìn)行微服務(wù)交互方式(微服務(wù)接口互相調(diào)用)

    使用FeignClient進(jìn)行微服務(wù)交互方式(微服務(wù)接口互相調(diào)用)

    這篇文章主要介紹了使用FeignClient進(jìn)行微服務(wù)交互方式(微服務(wù)接口互相調(diào)用),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Spring Cloud Gateway打造可擴展的微服務(wù)網(wǎng)關(guān)

    Spring Cloud Gateway打造可擴展的微服務(wù)網(wǎng)關(guān)

    微服務(wù)網(wǎng)關(guān)是一個位于客戶端和后端微服務(wù)之間的服務(wù)器,用于處理所有與客戶端的通信,Spring Cloud Gateway都是一個值得考慮的選擇,它將幫助您更好地管理和保護(hù)您的微服務(wù),感興趣的朋友一起看看吧
    2023-11-11
  • java Spring AOP詳解及簡單實例

    java Spring AOP詳解及簡單實例

    這篇文章主要介紹了java Spring AOP詳解及簡單實例的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 學(xué)生視角帶你了解Java內(nèi)部類

    學(xué)生視角帶你了解Java內(nèi)部類

    說起內(nèi)部類這個詞,想必很多人都不陌生,但是又會覺得不熟悉。原因是平時編寫代碼時可能用到的場景不多,用得最多的是在有事件監(jiān)聽的情況下,并且即使用到也很少去總結(jié)內(nèi)部類的用法。今天我們就來一探究竟
    2022-03-03
  • Spring調(diào)用this導(dǎo)致事務(wù)失效的三種解決方案

    Spring調(diào)用this導(dǎo)致事務(wù)失效的三種解決方案

    在 Spring 事務(wù)管理 中,如果你在同一個類的方法內(nèi)部使用 this.xxx() 調(diào)用另一個帶 @Transactional 的方法,事務(wù)很可能會失效,這不是玄學(xué),而是代理機制在背后打盹了,本文就給大家介紹如何解決this調(diào)用導(dǎo)致事務(wù)失效問題,需要的朋友可以參考下
    2026-02-02
  • 一篇文章帶你入門Java?UML的類圖

    一篇文章帶你入門Java?UML的類圖

    這篇文章主要為大家詳細(xì)介紹了Java?UML的類圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • 一小時迅速入門Mybatis之Prepared Statement與符號的使用

    一小時迅速入門Mybatis之Prepared Statement與符號的使用

    這篇文章主要介紹了一小時迅速入門Mybatis之Prepared Statement與符號的使用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09

最新評論

福清市| 石渠县| 抚宁县| 荥经县| 青海省| 武威市| 浦城县| 黄石市| 梁山县| 威远县| 汉源县| 湟源县| 台中市| 太康县| 漳浦县| 闽侯县| 榆树市| 皮山县| 济阳县| 延寿县| 阿坝| 临洮县| 澎湖县| 城口县| 利津县| 安平县| 宕昌县| 厦门市| 治多县| 桐城市| 乌审旗| 合川市| 柳林县| 泾阳县| 明水县| 贡嘎县| 临安市| 衡东县| 金堂县| 凤山县| 丰台区|