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

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 項目的過程涉及多個核心組件和自動化機(jī)制,下面從源碼角度詳細(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)用運(yùn)行中事件
    listeners.running(context);
    return context;
}

4. 嵌入式 Web 服務(wù)器啟動關(guān)鍵點(diǎ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)鍵點(diǎ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 初始化:配置請求映射、視圖解析等核心組件。

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

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

相關(guān)文章

  • Java HashMap算法原理詳細(xì)講解

    Java HashMap算法原理詳細(xì)講解

    在java開發(fā)中,HashMap是最常用、最常見的集合容器類之一,文中通過示例代碼介紹HashMap為啥要二次Hash,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-02-02
  • Spring事件監(jiān)聽基本原理與使用詳解

    Spring事件監(jiān)聽基本原理與使用詳解

    這篇文章主要介紹了Spring事件監(jiān)聽基本原理與使用詳解,Spring的事件監(jiān)聽機(jī)制和發(fā)布訂閱機(jī)制是很相似的:發(fā)布了一個事件后,監(jiān)聽該類型事件的所有監(jiān)聽器會觸發(fā)相應(yīng)的處理邏輯,需要的朋友可以參考下
    2024-01-01
  • Java8中關(guān)于Function.identity()的使用

    Java8中關(guān)于Function.identity()的使用

    這篇文章主要介紹了Java8中關(guān)于Function.identity()的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • 解析spring加載bean流程的方法

    解析spring加載bean流程的方法

    這篇文章主要介紹了解析spring加載bean流程的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • java中字符串如何計算字節(jié)長度

    java中字符串如何計算字節(jié)長度

    這篇文章主要介紹了java中字符串如何計算字節(jié)長度,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Spring整合Quartz Job以及Spring Task的實現(xiàn)方法

    Spring整合Quartz Job以及Spring Task的實現(xiàn)方法

    下面小編就為大家分享一篇Spring整合Quartz Job以及Spring Task的實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • Spring的事務(wù)控制實現(xiàn)方法

    Spring的事務(wù)控制實現(xiàn)方法

    這篇文章主要為大家詳細(xì)介紹了Spring的事務(wù)控制實現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Spring Boot與Kotlin定時任務(wù)的示例(Scheduling Tasks)

    Spring Boot與Kotlin定時任務(wù)的示例(Scheduling Tasks)

    這篇文章主要介紹了Spring Boot與Kotlin定時任務(wù)的示例(Scheduling Tasks),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • java正則表達(dá)式優(yōu)化超詳細(xì)舉例講解

    java正則表達(dá)式優(yōu)化超詳細(xì)舉例講解

    正則表達(dá)式是一種強(qiáng)大的文本處理工具,在數(shù)據(jù)驗證、字符串搜索和替換等方面有廣泛應(yīng)用,這篇文章主要介紹了java正則表達(dá)式優(yōu)化的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-07-07
  • SpringBoot 中實現(xiàn)跨域的5種方式小結(jié)

    SpringBoot 中實現(xiàn)跨域的5種方式小結(jié)

    這篇文章主要介紹了SpringBoot 中實現(xiàn)跨域的5種方式小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02

最新評論