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

SpringBoot中自動配置的完整啟動流程詳解

 更新時間:2026年04月03日 08:56:21   作者:用戶7914067968393  
這篇文章主要為大家詳細介紹了SpringBoot中自動配置的完整啟動流程,這是?Spring?Boot?最核心的機制,也是面試中屬于必考深度題,下面小編就和大家詳細介紹一下吧

好的,這是 Spring Boot 最核心的機制,面試中屬于必考深度題。我會從啟動入口到自動配置加載,完整拆解整個流程。

Spring Boot 啟動全流程

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

這行代碼背后發(fā)生了7個關鍵階段

階段一:構造 SpringApplication(實例化)

// SpringApplication.run() 內部
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return new SpringApplication(primarySource).run(args);  // 先構造,再運行
}

構造過程(推斷應用類型 + 加載初始化器):

步驟操作關鍵代碼
1. 推斷應用類型檢查類路徑判斷是 Servlet/Reactive/NoneWebApplicationType.deduceFromClasspath()
2. 加載 BootstrapRegistryInitializer從 spring.factories 加載getSpringFactoriesInstances()
3. 加載 ApplicationContextInitializer上下文初始化器同上
4. 加載 ApplicationListener應用事件監(jiān)聽器同上
5. 推斷主類通過堆棧分析找到包含 main 方法的類deduceMainApplicationClass()

推斷應用類型的邏輯

static WebApplicationType deduceFromClasspath() {
    if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", null)
            && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", null)) {
        return WebApplicationType.REACTIVE;  // WebFlux
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {  // Servlet 相關類
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;  // 非 Web
        }
    }
    return WebApplicationType.SERVLET;  // Spring MVC(默認)
}

階段二:運行 SpringApplication(run 方法核心)

public ConfigurableApplicationContext run(String... args) {
    // 1. 啟動計時器
    StartupStep startupStep = this.applicationStartup.start("spring.boot.application.starting");
    
    // 2. 創(chuàng)建 DefaultBootstrapContext(引導上下文)
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    
    ConfigurableApplicationContext context = null;
    
    // 3. 配置 Headless 模式(無顯示器環(huán)境)
    configureHeadlessProperty();
    
    // 4. 發(fā)布啟動事件(監(jiān)聽器可以在此介入)
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    
    try {
        // 5. 封裝命令行參數(shù)
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        
        // 6. 【關鍵】準備 Environment(加載配置文件)
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        
        // 7. 打印 Banner
        Banner printedBanner = printBanner(environment);
        
        // 8. 【關鍵】創(chuàng)建 ApplicationContext(根據(jù)類型創(chuàng)建)
        context = createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        
        // 9. 【核心】準備 Context(加載自動配置在此?。?
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        
        // 10. 【核心】刷新 Context(Bean 定義加載 + 實例化)
        refreshContext(context);
        
        // 11. 后置處理
        afterRefresh(context, applicationArguments);
        
        startupStep.end();
        listeners.started(context);
        
        // 12. 執(zhí)行 Runner(ApplicationRunner / CommandLineRunner)
        callRunners(context, applicationArguments);
        
    } catch (Throwable ex) {
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    
    listeners.running(context);
    return context;
}

階段三:準備 Environment(配置加載)

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
    
    // 1. 創(chuàng)建或獲取 Environment(StandardServletEnvironment)
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    
    // 2. 配置 PropertySources 和 Profiles
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    
    // 3. 【關鍵】發(fā)布環(huán)境準備事件,ConfigFileApplicationListener 響應
    //    這里加載 application.yml / application-{profile}.yml
    listeners.environmentPrepared(bootstrapContext, environment);
    
    return environment;
}

ConfigFileApplicationListener 的加載邏輯

加載順序(低優(yōu)先級 → 高優(yōu)先級,高覆蓋低)

1. jar 外部的 application-{profile}.properties/yml

2. jar 內部的 application-{profile}.properties/yml  

3. jar 外部的 application.properties/yml

4. jar 內部的 application.properties/yml

階段四:創(chuàng)建 ApplicationContext

protected ConfigurableApplicationContext createApplicationContext() {
    return this.applicationContextFactory.apply(this.webApplicationType);
}

// 根據(jù)類型創(chuàng)建不同上下文
switch (webApplicationType) {
    case SERVLET:
        // AnnotationConfigServletWebServerApplicationContext
        return new ServletWebServerApplicationContext();
    case REACTIVE:
        // AnnotationConfigReactiveWebServerApplicationContext  
        return new ReactiveWebServerApplicationContext();
    default:
        // AnnotationConfigApplicationContext
        return new ApplicationContext();
}

階段五:準備 Context(【核心】自動配置入口)

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments, Banner printedBanner) {
    
    // 1. 設置 Environment
    context.setEnvironment(environment);
    
    // 2. 后置處理 Context(注冊 beanNameGenerator、resourceLoader 等)
    postProcessApplicationContext(context);
    
    // 3. 【關鍵】執(zhí)行 ApplicationContextInitializer
    applyInitializers(context);
    
    // 4. 發(fā)布 ContextPrepared 事件
    listeners.contextPrepared(context);
    
    // 5. 注冊 Spring Boot 特殊 Bean
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    
    // 6. 【核心】加載主類(@SpringBootApplication 所在類)
    Set<Object> sources = getAllSources();
    load(context, sources.toArray(new Object[0]));  // 注冊為 BeanDefinition
    
    // 7. 發(fā)布 ContextLoaded 事件
    listeners.contextLoaded(context);
}

階段六:刷新 Context(【核心】自動配置加載)

refreshContext()AbstractApplicationContext.refresh()

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 準備刷新(設置啟動時間、狀態(tài)等)
        prepareRefresh();
        
        // 2. 獲取 BeanFactory(DefaultListableBeanFactory)
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        
        // 3. 準備 BeanFactory(注冊類加載器、表達式解析器等)
        prepareBeanFactory(beanFactory);
        
        try {
            // 4. 子類擴展(ServletContext 相關處理)
            postProcessBeanFactory(beanFactory);
            
            // 5. 【關鍵】執(zhí)行 BeanFactoryPostProcessor
            //    ConfigurationClassPostProcessor 在這里處理 @Configuration 類
            invokeBeanFactoryPostProcessors(beanFactory);
            
            // 6. 注冊 BeanPostProcessor
            registerBeanPostProcessors(beanFactory);
            
            // 7. 初始化 MessageSource
            initMessageSource();
            
            // 8. 初始化 ApplicationEventMulticaster
            initApplicationEventMulticaster();
            
            // 9. 子類擴展(創(chuàng)建 WebServer,如 Tomcat)
            onRefresh();
            
            // 10. 注冊監(jiān)聽器
            registerListeners();
            
            // 11. 【關鍵】實例化所有非懶加載的單例 Bean
            finishBeanFactoryInitialization(beanFactory);
            
            // 12. 完成刷新(發(fā)布 ContextRefreshedEvent)
            finishRefresh();
        }
        // ...
    }
}

核心:invokeBeanFactoryPostProcessors

// ConfigurationClassPostProcessor 處理 @Configuration 類
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 解析 @Configuration 類,包括 @ComponentScan、@Import、@Bean 等
    processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}

解析主類的 @SpringBootApplication

@SpringBootApplication  // 組合注解
public class Application { }

// 等價于:
@Configuration
@EnableAutoConfiguration      // 【核心】開啟自動配置
@ComponentScan                // 組件掃描
public class Application { }

階段七:@EnableAutoConfiguration 原理

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage      // 將主類所在包注冊為自動配置包
@Import(AutoConfigurationImportSelector.class)  // 【核心】導入自動配置類
public @interface EnableAutoConfiguration {}

AutoConfigurationImportSelector 加載流程

public class AutoConfigurationImportSelector implements 
        DeferredImportSelector, BeanClassLoaderAware, ... {
    
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 1. 檢查是否啟用自動配置(spring.boot.enableautoconfiguration)
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        
        // 2. 從 META-INF/spring-autoconfigure-metadata.properties 加載元數(shù)據(jù)
        AutoConfigurationMetadata autoConfigurationMetadata = 
            AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
        
        // 3. 【關鍵】獲取候選自動配置類
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        
        // 4. 去重
        configurations = removeDuplicates(configurations);
        
        // 5. 獲取需要排除的類(@EnableAutoConfiguration(exclude=...))
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        
        // 6. 檢查排除類合法性
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        
        // 7. 【關鍵】按條件過濾(@Conditional 評估)
        configurations = getConfigurationClassFilter().filter(configurations);
        
        // 8. 發(fā)布自動配置導入事件
        fireAutoConfigurationImportEvents(configurations, exclusions);
        
        return StringUtils.toStringArray(configurations);
    }
}

獲取候選配置類(SPI 機制)

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, 
        AnnotationAttributes attributes) {
    // 從 META-INF/spring.factories 加載
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
        getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    
    Assert.notEmpty(configurations, 
        "No auto configuration classes found in META-INF/spring.factories");
    
    return configurations;
}

// spring.factories 示例(Spring Boot 2.7+ 改為 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
...(約 100+ 個)

條件過濾(@Conditional 生效)

private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
    long startTime = System.nanoTime();
    String[] candidates = StringUtils.toStringArray(configurations);
    boolean[] skip = new boolean[candidates.length];
    boolean skipped = false;
    
    // 獲取所有條件過濾器(OnClassCondition, OnBeanCondition, OnPropertyCondition 等)
    for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
        invokeAwareMethods(filter);
        
        // 批量匹配條件(優(yōu)化性能,避免每個類單獨檢查)
        boolean[] match = filter.match(candidates, autoConfigurationMetadata);
        
        for (int i = 0; i < match.length; i++) {
            if (!match[i]) {
                skip[i] = true;
                candidates[i] = null;  // 標記為跳過
                skipped = true;
            }
        }
    }
    
    // 收集通過的類
    if (!skipped) {
        return configurations;
    }
    List<String> result = new ArrayList<>(candidates.length);
    for (int i = 0; i < candidates.length; i++) {
        if (!skip[i]) {
            result.add(candidates[i]);
        }
    }
    return result;
}

完整流程圖

┌─────────────────────────────────────────────────────────────────┐
│                    SpringApplication.run()                        │
├─────────────────────────────────────────────────────────────────┤
│  1. 構造 SpringApplication                                       │
│     ├── 推斷 Web 類型 (Servlet/Reactive/None)                    │
│     ├── 加載 spring.factories: BootstrapRegistryInitializer      │
│     ├── 加載 spring.factories: ApplicationContextInitializer     │
│     └── 加載 spring.factories: ApplicationListener               │
├─────────────────────────────────────────────────────────────────┤
│  2. 運行 run()                                                   │
│     ├── 發(fā)布 Starting 事件                                       │
│     ├── 準備 Environment(加載 application.yml)                 │
│     ├── 打印 Banner                                              │
│     ├── 創(chuàng)建 ApplicationContext                                  │
│     ├── 準備 Context                                             │
│     │   ├── 執(zhí)行 ApplicationContextInitializer                   │
│     │   ├── 加載主類(@SpringBootApplication)                   │
│     │   └── 發(fā)布 ContextPrepared/ContextLoaded 事件              │
│     ├── 【核心】刷新 Context                                      │
│     │   ├── invokeBeanFactoryPostProcessors                      │
│     │   │   └── ConfigurationClassPostProcessor                  │
│     │   │       └── 解析 @Configuration                          │
│     │   │           ├── 處理 @ComponentScan(包掃描)             │
│     │   │           ├── 處理 @Import(導入配置類)                 │
│     │   │           │   └── @EnableAutoConfiguration            │
│     │   │           │       └── AutoConfigurationImportSelector   │
│     │   │           │           ├── 讀取 spring.factories         │
│     │   │           │           ├── 獲取 100+ 自動配置類            │
│     │   │           │           ├── @Conditional 過濾            │
│     │   │           │           │   ├── OnClassCondition         │
│     │   │           │           │   ├── OnBeanCondition          │
│     │   │           │           │   └── OnPropertyCondition      │
│     │   │           │           └── 注冊通過的 BeanDefinition     │
│     │   │           └── 處理 @Bean 方法                          │
│     │   ├── 注冊 BeanPostProcessor                               │
│     │   ├── onRefresh()(創(chuàng)建 WebServer,如 Tomcat)              │
│     │   ├── finishBeanFactoryInitialization(實例化單例 Bean)     │
│     │   └── finishRefresh()                                      │
│     ├── 執(zhí)行 ApplicationRunner / CommandLineRunner               │
│     └── 發(fā)布 Running 事件                                        │
└─────────────────────────────────────────────────────────────────┘
 

關鍵優(yōu)化點(面試加分項)

優(yōu)化說明版本
spring-autoconfigure-metadata.properties編譯期生成條件元數(shù)據(jù),避免運行時反射檢查類是否存在2.0+
DeferredImportSelector延遲導入,確保用戶配置優(yōu)先于自動配置1.5+
批量條件評估一次檢查多個類,減少 ClassLoader 查詢次數(shù)2.0+
AOT 處理(Spring Boot 3+)原生鏡像支持,啟動時無需反射掃描3.0+

面試回答模板

"Spring Boot 啟動流程分為構造和運行兩個階段。構造階段推斷應用類型、加載初始化器;運行階段先準備 Environment 加載配置文件,然后創(chuàng)建 ApplicationContext。核心是 refresh 過程,其中 ConfigurationClassPostProcessor 解析主類的 @SpringBootApplication,觸發(fā)@EnableAutoConfiguration,通過 AutoConfigurationImportSelector 從 spring.factories 讀取自動配置類,再經(jīng)過 @Conditional 條件過濾,最終注冊符合條件的 BeanDefinition 到容器。"

到此這篇關于SpringBoot中自動配置的完整啟動流程詳解的文章就介紹到這了,更多相關SpringBoot自動配置內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot Redis緩存數(shù)據(jù)實現(xiàn)解析

    SpringBoot Redis緩存數(shù)據(jù)實現(xiàn)解析

    這篇文章主要介紹了SpringBoot Redis緩存數(shù)據(jù)實現(xiàn)解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • java按指定編碼寫入和讀取文件內容的類分享

    java按指定編碼寫入和讀取文件內容的類分享

    這篇文章主要介紹了java按指定編碼寫入和讀取文件內容的類,需要的朋友可以參考下
    2014-02-02
  • Java中消息隊列任務的平滑關閉詳解

    Java中消息隊列任務的平滑關閉詳解

    對于消息隊列的監(jiān)聽,我們一般使用Java寫一個獨立的程序,在Linux服務器上運行。程序啟動后,通過消息隊列客戶端接收消息,放入一個線程池進行異步處理,并發(fā)的快速處理。這篇文章主要給大家介紹了關于Java中消息隊列任務的平滑關閉的相關資料,需要的朋友可以參考下。
    2017-11-11
  • Java設計模式之模板方法模式Template Method Pattern詳解

    Java設計模式之模板方法模式Template Method Pattern詳解

    在我們實際開發(fā)中,如果一個方法極其復雜時,如果我們將所有的邏輯寫在一個方法中,那維護起來就很困難,要替換某些步驟時都要重新寫,這樣代碼的擴展性就很差,當遇到這種情況就要考慮今天的主角——模板方法模式
    2022-11-11
  • 關于MyBatis中Mapper?XML熱加載優(yōu)化

    關于MyBatis中Mapper?XML熱加載優(yōu)化

    大家好,本篇文章主要講的是關于MyBatis中Mapper?XML熱加載優(yōu)化,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • 關于Java 并發(fā)的 CAS

    關于Java 并發(fā)的 CAS

    后端開發(fā)鎖成為一個不可避免的話題,今天我們討論的是與之對應的無鎖 CAS。本文會從怎么來的、是什么、怎么用、原理分析、遇到的問題等不同的角度帶你真正搞懂 CAS。
    2021-09-09
  • java springboot的概述、特點與構建介紹

    java springboot的概述、特點與構建介紹

    大家好,本篇文章主要講的是springboot的概述、特點與構建介紹,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • 郵件的組織結構介紹 郵件實現(xiàn)詳解(三)

    郵件的組織結構介紹 郵件實現(xiàn)詳解(三)

    這篇文章主要為大家詳細介紹了郵件的組織結構,郵件內容的基本格式和具體細節(jié),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Java你告訴我 fail-fast 是什么鬼

    Java你告訴我 fail-fast 是什么鬼

    這篇文章主要介紹了Java你告訴我 fail-fast 是什么鬼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • Java線程并發(fā)工具類CountDownLatch原理及用法

    Java線程并發(fā)工具類CountDownLatch原理及用法

    這篇文章主要介紹了Java線程并發(fā)工具類CountDownLatch原理及用法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10

最新評論

泾阳县| 岐山县| 临沂市| 左云县| 三亚市| 琼结县| 宜昌市| 波密县| 澎湖县| 社旗县| 那曲县| 康保县| 蒙城县| 承德县| 九江市| 黔南| 永吉县| 通化市| 三原县| 富顺县| 盐山县| 湘潭县| 茂名市| 遂川县| 高陵县| 吉林省| 沅江市| 石家庄市| 金塔县| 加查县| 沙田区| 崇左市| 顺义区| 筠连县| 阳曲县| 黄骅市| 汤原县| 胶州市| 淮滨县| 云梦县| 泌阳县|