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

SpringBoot中自動(dòng)配置的完整啟動(dòng)流程詳解

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

好的,這是 Spring Boot 最核心的機(jī)制,面試中屬于必考深度題。我會(huì)從啟動(dòng)入口到自動(dòng)配置加載,完整拆解整個(gè)流程。

Spring Boot 啟動(dòng)全流程

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

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

階段一:構(gòu)造 SpringApplication(實(shí)例化)

// SpringApplication.run() 內(nèi)部
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return new SpringApplication(primarySource).run(args);  // 先構(gòu)造,再運(yùn)行
}

構(gòu)造過(guò)程(推斷應(yīng)用類型 + 加載初始化器):

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

推斷應(yīng)用類型的邏輯

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 相關(guān)類
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;  // 非 Web
        }
    }
    return WebApplicationType.SERVLET;  // Spring MVC(默認(rèn))
}

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

public ConfigurableApplicationContext run(String... args) {
    // 1. 啟動(dòng)計(jì)時(shí)器
    StartupStep startupStep = this.applicationStartup.start("spring.boot.application.starting");
    
    // 2. 創(chuàng)建 DefaultBootstrapContext(引導(dǎo)上下文)
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    
    ConfigurableApplicationContext context = null;
    
    // 3. 配置 Headless 模式(無(wú)顯示器環(huán)境)
    configureHeadlessProperty();
    
    // 4. 發(fā)布啟動(dòng)事件(監(jiān)聽器可以在此介入)
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    
    try {
        // 5. 封裝命令行參數(shù)
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        
        // 6. 【關(guān)鍵】準(zhǔn)備 Environment(加載配置文件)
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        
        // 7. 打印 Banner
        Banner printedBanner = printBanner(environment);
        
        // 8. 【關(guān)鍵】創(chuàng)建 ApplicationContext(根據(jù)類型創(chuàng)建)
        context = createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        
        // 9. 【核心】準(zhǔn)備 Context(加載自動(dòng)配置在此?。?
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        
        // 10. 【核心】刷新 Context(Bean 定義加載 + 實(shí)例化)
        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;
}

階段三:準(zhǔn)備 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. 【關(guān)鍵】發(fā)布環(huán)境準(zhǔn)備事件,ConfigFileApplicationListener 響應(yīng)
    //    這里加載 application.yml / application-{profile}.yml
    listeners.environmentPrepared(bootstrapContext, environment);
    
    return environment;
}

ConfigFileApplicationListener 的加載邏輯

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

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

2. jar 內(nèi)部的 application-{profile}.properties/yml  

3. jar 外部的 application.properties/yml

4. jar 內(nèi)部的 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();
}

階段五:準(zhǔn)備 Context(【核心】自動(dòng)配置入口)

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments, Banner printedBanner) {
    
    // 1. 設(shè)置 Environment
    context.setEnvironment(environment);
    
    // 2. 后置處理 Context(注冊(cè) beanNameGenerator、resourceLoader 等)
    postProcessApplicationContext(context);
    
    // 3. 【關(guān)鍵】執(zhí)行 ApplicationContextInitializer
    applyInitializers(context);
    
    // 4. 發(fā)布 ContextPrepared 事件
    listeners.contextPrepared(context);
    
    // 5. 注冊(cè) 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]));  // 注冊(cè)為 BeanDefinition
    
    // 7. 發(fā)布 ContextLoaded 事件
    listeners.contextLoaded(context);
}

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

refreshContext()AbstractApplicationContext.refresh()

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

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

階段七:@EnableAutoConfiguration 原理

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

AutoConfigurationImportSelector 加載流程

public class AutoConfigurationImportSelector implements 
        DeferredImportSelector, BeanClassLoaderAware, ... {
    
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 1. 檢查是否啟用自動(dòng)配置(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. 【關(guān)鍵】獲取候選自動(dòng)配置類
        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. 【關(guān)鍵】按條件過(guò)濾(@Conditional 評(píng)估)
        configurations = getConfigurationClassFilter().filter(configurations);
        
        // 8. 發(fā)布自動(dòng)配置導(dǎo)入事件
        fireAutoConfigurationImportEvents(configurations, exclusions);
        
        return StringUtils.toStringArray(configurations);
    }
}

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

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+ 個(gè))

條件過(guò)濾(@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;
    
    // 獲取所有條件過(guò)濾器(OnClassCondition, OnBeanCondition, OnPropertyCondition 等)
    for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
        invokeAwareMethods(filter);
        
        // 批量匹配條件(優(yōu)化性能,避免每個(gè)類單獨(dú)檢查)
        boolean[] match = filter.match(candidates, autoConfigurationMetadata);
        
        for (int i = 0; i < match.length; i++) {
            if (!match[i]) {
                skip[i] = true;
                candidates[i] = null;  // 標(biāo)記為跳過(guò)
                skipped = true;
            }
        }
    }
    
    // 收集通過(guò)的類
    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. 構(gòu)造 SpringApplication                                       │
│     ├── 推斷 Web 類型 (Servlet/Reactive/None)                    │
│     ├── 加載 spring.factories: BootstrapRegistryInitializer      │
│     ├── 加載 spring.factories: ApplicationContextInitializer     │
│     └── 加載 spring.factories: ApplicationListener               │
├─────────────────────────────────────────────────────────────────┤
│  2. 運(yùn)行 run()                                                   │
│     ├── 發(fā)布 Starting 事件                                       │
│     ├── 準(zhǔn)備 Environment(加載 application.yml)                 │
│     ├── 打印 Banner                                              │
│     ├── 創(chuàng)建 ApplicationContext                                  │
│     ├── 準(zhǔn)備 Context                                             │
│     │   ├── 執(zhí)行 ApplicationContextInitializer                   │
│     │   ├── 加載主類(@SpringBootApplication)                   │
│     │   └── 發(fā)布 ContextPrepared/ContextLoaded 事件              │
│     ├── 【核心】刷新 Context                                      │
│     │   ├── invokeBeanFactoryPostProcessors                      │
│     │   │   └── ConfigurationClassPostProcessor                  │
│     │   │       └── 解析 @Configuration                          │
│     │   │           ├── 處理 @ComponentScan(包掃描)             │
│     │   │           ├── 處理 @Import(導(dǎo)入配置類)                 │
│     │   │           │   └── @EnableAutoConfiguration            │
│     │   │           │       └── AutoConfigurationImportSelector   │
│     │   │           │           ├── 讀取 spring.factories         │
│     │   │           │           ├── 獲取 100+ 自動(dòng)配置類            │
│     │   │           │           ├── @Conditional 過(guò)濾            │
│     │   │           │           │   ├── OnClassCondition         │
│     │   │           │           │   ├── OnBeanCondition          │
│     │   │           │           │   └── OnPropertyCondition      │
│     │   │           │           └── 注冊(cè)通過(guò)的 BeanDefinition     │
│     │   │           └── 處理 @Bean 方法                          │
│     │   ├── 注冊(cè) BeanPostProcessor                               │
│     │   ├── onRefresh()(創(chuàng)建 WebServer,如 Tomcat)              │
│     │   ├── finishBeanFactoryInitialization(實(shí)例化單例 Bean)     │
│     │   └── finishRefresh()                                      │
│     ├── 執(zhí)行 ApplicationRunner / CommandLineRunner               │
│     └── 發(fā)布 Running 事件                                        │
└─────────────────────────────────────────────────────────────────┘
 

關(guān)鍵優(yōu)化點(diǎn)(面試加分項(xiàng))

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

面試回答模板

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

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

相關(guān)文章

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

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

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

    java按指定編碼寫入和讀取文件內(nèi)容的類分享

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

    Java中消息隊(duì)列任務(wù)的平滑關(guān)閉詳解

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

    Java設(shè)計(jì)模式之模板方法模式Template Method Pattern詳解

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

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

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

    關(guān)于Java 并發(fā)的 CAS

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

    java springboot的概述、特點(diǎn)與構(gòu)建介紹

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

    郵件的組織結(jié)構(gòu)介紹 郵件實(shí)現(xiàn)詳解(三)

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

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

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

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

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

最新評(píng)論

神农架林区| 灵宝市| 长乐市| 砀山县| 荣成市| 安庆市| 绥江县| 宜宾县| 罗源县| 东辽县| 元江| 麦盖提县| 淅川县| 岳池县| 朔州市| 余庆县| 承德县| 平南县| 永靖县| 团风县| 苏尼特右旗| 临洮县| 武城县| 清水县| 郯城县| 无棣县| 江川县| 志丹县| 彰化县| 安国市| 乌兰浩特市| 岐山县| 昌宁县| 吉林省| 鹰潭市| 寿宁县| 延吉市| 峡江县| 嘉善县| 洛南县| 呼和浩特市|