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

Spring Boot啟動(dòng)流程示例詳解

 更新時(shí)間:2026年02月10日 11:21:32   作者:探索java  
Spring Boot是Spring官方推出的一個(gè)快速構(gòu)建獨(dú)立運(yùn)行、生產(chǎn)級(jí)別Spring應(yīng)用的框架,它的核心目標(biāo)是簡化Spring應(yīng)用的搭建與部署,本文給大家介紹Spring Boot啟動(dòng)流程詳解,感興趣的朋友跟隨小編一起看看吧

1. Spring Boot啟動(dòng)流程概述

1.1 Spring Boot的核心特性

Spring Boot是Spring官方推出的一個(gè)快速構(gòu)建獨(dú)立運(yùn)行、生產(chǎn)級(jí)別Spring應(yīng)用的框架,它的核心目標(biāo)是簡化Spring應(yīng)用的搭建與部署。
核心特性主要包括:

  • 內(nèi)嵌Web容器
  • 內(nèi)置Tomcat、Jetty、Undertow,無需單獨(dú)部署WAR包到外部容器。只需運(yùn)行java -jar即可啟動(dòng)。
  • 自動(dòng)配置(Auto Configuration)
  • 通過@EnableAutoConfiguration結(jié)合條件化裝配(Conditional注解)自動(dòng)為應(yīng)用注冊(cè)Bean,大幅減少xml或Java配置的編寫量。
  • 獨(dú)立運(yùn)行(Standalone)
  • 應(yīng)用可以以一個(gè)獨(dú)立的JAR包形式運(yùn)行,避免復(fù)雜的服務(wù)器配置。
  • 起步依賴(Starter Dependencies)
  • 提供spring-boot-starter-*依賴包,按需引入常用功能,減少手動(dòng)管理依賴的復(fù)雜度。
  • 生產(chǎn)環(huán)境特性
  • 提供Actuator監(jiān)控、健康檢查、環(huán)境信息、度量指標(biāo)等。

類比:可以把Spring Boot想象成“開箱即用的開發(fā)平臺(tái)”,你不需要自己組裝各種組件,它已經(jīng)幫你準(zhǔn)備好了一整套“工具箱”和“默認(rèn)配置”。

1.2 啟動(dòng)流程整體架構(gòu)(文字描述)

Spring Boot啟動(dòng)的核心流程可以抽象成五個(gè)階段:

  • 初始化SpringApplication
    • 解析啟動(dòng)類(@SpringBootApplication標(biāo)注的類)
    • 推斷應(yīng)用類型(WebApplicationType
    • 加載初始化器(ApplicationContextInitializer
    • 加載監(jiān)聽器(ApplicationListener
  • 準(zhǔn)備運(yùn)行環(huán)境(Environment)
    • 創(chuàng)建并配置Environment對(duì)象
    • 加載外部配置(命令行參數(shù)、配置文件、系統(tǒng)屬性等)
    • 配置轉(zhuǎn)換器(PropertySource -> Environment
  • 創(chuàng)建并刷新ApplicationContext
    • 根據(jù)應(yīng)用類型創(chuàng)建合適的ApplicationContext(Servlet、Reactive或普通應(yīng)用)
    • 注冊(cè)Bean定義、執(zhí)行BeanFactoryPostProcessorBeanPostProcessor
    • 啟動(dòng)內(nèi)嵌Web容器(如Tomcat)
  • 自動(dòng)配置與Bean加載
    • 解析@EnableAutoConfiguration加載自動(dòng)配置類
    • 條件化裝配判斷是否加載特定Bean
    • 初始化所有單例Bean
  • 完成啟動(dòng)并執(zhí)行回調(diào)
    • 發(fā)布ApplicationReadyEvent事件
    • 執(zhí)行CommandLineRunnerApplicationRunner

文字版的啟動(dòng)時(shí)序:
SpringApplication實(shí)例化 -> 推斷Web類型 -> 加載監(jiān)聽器 -> 創(chuàng)建Environment -> 加載配置 -> 創(chuàng)建ApplicationContext -> 自動(dòng)配置 -> 啟動(dòng)容器 -> 應(yīng)用就緒

1.3 Spring Boot 2.x 與 3.x 啟動(dòng)機(jī)制差異

在Spring Boot 3.x(基于Spring Framework 6)中,啟動(dòng)流程的總體框架與2.x一致,但有一些細(xì)節(jié)變化:

  • WebApplicationType推斷優(yōu)化
    • Spring Boot 3.x在推斷應(yīng)用類型時(shí),對(duì)org.springframework.web.reactive.DispatcherHandler等類的檢測(cè)進(jìn)行了微調(diào),更精確地區(qū)分Servlet與Reactive應(yīng)用。
  • SpringFactoriesLoader升級(jí)
    • 2.x版本讀取META-INF/spring.factories文件使用Properties加載,3.x版本引入了新的API(SpringFactoriesLoader.forDefaultResourceLocation()),并且支持META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,提高了加載性能。
  • BootstrapContext增強(qiáng)
    • 3.x版本中BootstrapContext在啟動(dòng)階段的使用更靈活,可以在應(yīng)用啟動(dòng)前注冊(cè)額外的組件。
  • Jakarta命名空間遷移
    • 所有與Servlet相關(guān)的類名由javax.*遷移到jakarta.*,這在3.x升級(jí)時(shí)需要特別注意。

示例:最簡單的Spring Boot引導(dǎo)類

package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
 * @SpringBootApplication 是三個(gè)注解的組合:
 * - @Configuration:表示該類是一個(gè)配置類
 * - @EnableAutoConfiguration:開啟自動(dòng)配置
 * - @ComponentScan:開啟包掃描
 */
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        // run方法會(huì)啟動(dòng)整個(gè)Spring Boot應(yīng)用
        SpringApplication.run(DemoApplication.class, args);
    }
}

運(yùn)行上面的程序,你會(huì)在控制臺(tái)看到類似輸出(簡化版):

:: Spring Boot ::        (v3.2.0)
2025-08-11 10:15:00  INFO  --- Starting DemoApplication on localhost with PID 12345
2025-08-11 10:15:01  INFO  --- Tomcat started on port(s): 8080 (http)
2025-08-11 10:15:01  INFO  --- Started DemoApplication in 1.234 seconds

2. Spring Boot啟動(dòng)的核心階段

2.1 SpringApplication初始化階段

當(dāng)你調(diào)用:

SpringApplication.run(DemoApplication.class, args);

實(shí)際上會(huì)先執(zhí)行 new SpringApplication(primarySources...) 構(gòu)造方法,再執(zhí)行 .run(args) 方法。

源碼入口(Spring Boot 2.x / 3.x)

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 推斷應(yīng)用類型(Servlet / Reactive / None)
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 從 spring.factories 加載 ApplicationContextInitializer
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 從 spring.factories 加載 ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 推斷并設(shè)置 main 方法所在類
    this.mainApplicationClass = deduceMainApplicationClass();
}

幾個(gè)關(guān)鍵點(diǎn):

  • 推斷 WebApplicationType
    • 如果classpath中存在DispatcherServlet,就認(rèn)為是Servlet類型應(yīng)用;
    • 如果存在DispatcherHandler,就認(rèn)為是Reactive類型應(yīng)用;
    • 否則是普通的NONE類型(無Web環(huán)境)。
  • 加載初始化器(Initializers)
    • 通過SpringFactoriesLoader掃描META-INF/spring.factories,自動(dòng)實(shí)例化所有ApplicationContextInitializer實(shí)現(xiàn)類。
  • 加載監(jiān)聽器(Listeners)
    • 同樣用SpringFactoriesLoader機(jī)制加載ApplicationListener實(shí)現(xiàn)類,用于監(jiān)聽?wèi)?yīng)用啟動(dòng)過程的事件。
  • 推斷Main類
    • 遍歷當(dāng)前線程的調(diào)用棧,找到第一個(gè)包含main方法的類。

示例:自定義ApplicationContextInitializer

public class MyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        System.out.println("MyInitializer: 應(yīng)用上下文初始化中...");
    }
}

resources/META-INF/spring.factories

org.springframework.context.ApplicationContextInitializer=\
com.example.demo.MyInitializer

啟動(dòng)時(shí)會(huì)先輸出:

MyInitializer: 應(yīng)用上下文初始化中...

說明在SpringApplication構(gòu)造時(shí)已成功加載該初始化器。

2.2 SpringApplication.run()執(zhí)行過程全解析

SpringApplication.run() 是整個(gè)啟動(dòng)的核心,下面是簡化后的源碼執(zhí)行順序(以3.x為例):

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    // 啟動(dòng)監(jiān)聽器集合
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    // 初始化引導(dǎo)上下文(BootstrapContext)
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    // 創(chuàng)建并配置 Environment
    ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, args);
    // 打印 Banner
    Banner printedBanner = printBanner(environment);
    // 創(chuàng)建 ApplicationContext
    context = createApplicationContext();
    // 準(zhǔn)備上下文
    prepareContext(bootstrapContext, context, environment, listeners, args, printedBanner);
    // 刷新上下文(加載Bean、啟動(dòng)內(nèi)嵌容器)
    refreshContext(context);
    // 執(zhí)行 CommandLineRunner、ApplicationRunner
    afterRefresh(context, args);
    stopWatch.stop();
    if (this.logStartupInfo) {
        new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    }
    listeners.started(context);
    listeners.running(context);
    return context;
}

分步驟解析:

  • StopWatch計(jì)時(shí)器
    • 用于記錄啟動(dòng)耗時(shí),最終會(huì)在日志輸出Started Xxx in 2.345 seconds。
  • 啟動(dòng)監(jiān)聽器(SpringApplicationRunListeners)
    • 觸發(fā)ApplicationStartingEvent事件,可以在這里做日志或系統(tǒng)初始化。
  • 創(chuàng)建BootstrapContext
    • 啟動(dòng)早期用于注冊(cè)額外組件,如配置加載器(Spring Cloud 會(huì)用到)。
  • 創(chuàng)建并準(zhǔn)備Environment
    • 加載外部配置(命令行、配置文件、環(huán)境變量)。
    • 設(shè)置PropertySource的加載順序。
  • 打印Banner
    • 控制臺(tái)輸出Spring Boot ASCII藝術(shù)字,可以自定義。
  • 創(chuàng)建ApplicationContext
    • 根據(jù)Web類型創(chuàng)建AnnotationConfigServletWebServerApplicationContextAnnotationConfigApplicationContext。
  • prepareContext
    • 注冊(cè)初始化器(Initializer)。
    • 注冊(cè)監(jiān)聽器(Listener)。
    • 注冊(cè)主配置類(啟動(dòng)類)。
  • refreshContext
    • 調(diào)用Spring核心的refresh()方法,完成Bean的加載、依賴注入、事件注冊(cè)等。
  • 執(zhí)行Runner回調(diào)
    • CommandLineRunnerApplicationRunner用于啟動(dòng)完成后的業(yè)務(wù)處理。
  • 觸發(fā)應(yīng)用就緒事件
    • 發(fā)布ApplicationReadyEvent,代表應(yīng)用完全啟動(dòng)并可對(duì)外提供服務(wù)。

示例:監(jiān)聽啟動(dòng)事件

@Component
public class MyStartupListener implements ApplicationListener<ApplicationStartingEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartingEvent event) {
        System.out.println("應(yīng)用啟動(dòng)中:執(zhí)行早期初始化邏輯...");
    }
}

2.3 WebApplicationType推斷機(jī)制

源碼(簡化):

public static WebApplicationType deduceFromClasspath() {
    if (ClassUtils.isPresent(REACTIVE_DISPATCHER, null) && !ClassUtils.isPresent(DISPATCHER_SERVLET, null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}

判斷邏輯:

  • 如果存在org.springframework.web.reactive.DispatcherHandler且不存在DispatcherServlet → REACTIVE
  • 如果缺少Servlet必要類 → NONE
  • 其他情況默認(rèn)SERVLET

?? 小結(jié)

  • SpringApplication構(gòu)造階段主要是推斷類型、加載初始化器、監(jiān)聽器。
  • run()方法則是準(zhǔn)備環(huán)境、創(chuàng)建上下文、刷新Bean、執(zhí)行回調(diào)的全過程。
  • Web類型推斷保證了Spring Boot能自動(dòng)適配不同類型的應(yīng)用(Servlet、Reactive、None)。

3. 環(huán)境準(zhǔn)備與配置加載

3.1 Environment對(duì)象的創(chuàng)建與類型

在 Spring Boot 啟動(dòng)時(shí),會(huì)根據(jù)應(yīng)用類型(WebApplicationType)來創(chuàng)建不同的 Environment 實(shí)現(xiàn)類:

應(yīng)用類型Environment實(shí)現(xiàn)類
SERVLETStandardServletEnvironment
REACTIVEStandardReactiveWebEnvironment
NONEStandardEnvironment

源碼位置(SpringApplication.prepareEnvironment)

private ConfigurableEnvironment getOrCreateEnvironment() {
    if (this.environment != null) {
        return this.environment;
    }
    switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
    }
}

Environment 作用

  • 存放應(yīng)用的配置源(PropertySource)。
  • 提供配置值的統(tǒng)一獲取接口(getProperty)。
  • 提供 profile 管理(setActiveProfiles)。

小示例:獲取Environment對(duì)象

@Component
public class EnvPrinter implements CommandLineRunner {
    @Autowired
    private Environment environment;
    @Override
    public void run(String... args) {
        System.out.println("當(dāng)前激活的profile: " + Arrays.toString(environment.getActiveProfiles()));
        System.out.println("server.port=" + environment.getProperty("server.port"));
    }
}

運(yùn)行時(shí)會(huì)輸出配置文件或命令行參數(shù)中對(duì)應(yīng)的值。

3.2 配置源加載順序與優(yōu)先級(jí)

Spring Boot 的配置加載是有優(yōu)先級(jí)順序的,后加載的會(huì)覆蓋先加載的。

官方的 優(yōu)先級(jí)順序(從高到低)

  • 命令行參數(shù)
    • --server.port=9000
  • Java系統(tǒng)屬性
    • System.setProperty("server.port", "9000")
  • 操作系統(tǒng)環(huán)境變量
    • application-{profile}.properties(當(dāng)前激活的 profile 配置)
    • application.properties / application.yml
  • 打包在 jar 外部的配置文件(優(yōu)先于 jar 內(nèi)部配置文件)
  • 打包在 jar 內(nèi)部的配置文件
    • 默認(rèn)配置(代碼中 SpringApplication.setDefaultProperties() 設(shè)置)

命令行參數(shù)覆蓋示例

假設(shè) application.properties 中配置:

server.port=8080

運(yùn)行:

java -jar demo.jar --server.port=9001

最終生效端口是 9001,因?yàn)槊钚袇?shù)優(yōu)先級(jí)最高。

3.3 application.properties 與 application.yml 加載規(guī)則

Spring Boot 支持 .properties.yml 兩種格式,加載順序(同一位置)是:

  • 先加載 .properties
  • 再加載 .yml

并且,配置文件可以放在多個(gè)位置:

  • classpath:/
  • classpath:/config/
  • file:./
  • file:./config/

優(yōu)先級(jí)順序(從高到低)

  • file:./config/
  • file:./
  • classpath:/config/
  • classpath:/

3.4 命令行參數(shù)、系統(tǒng)屬性覆蓋規(guī)則

Spring Boot 會(huì)自動(dòng)將命令行參數(shù)解析成 PropertySource 并加入 Environment,它們的優(yōu)先級(jí)高于配置文件。

源碼位置

protected void configureEnvironment(ConfigurableEnvironment environment,
                                    String[] args) {
    new CommandLinePropertySource<>("commandLineArgs", args);
}

命令行參數(shù)會(huì)被解析成 key-value 形式,覆蓋之前加載的同名配置。

3.5 @Value 與 @ConfigurationProperties 獲取配置

@Value

直接從 Environment 中取值:

@Value("${server.port}")
private int port;

@ConfigurationProperties

批量綁定配置到 Java Bean:

@Component
@ConfigurationProperties(prefix = "myapp")
public class MyAppConfig {
    private String name;
    private int timeout;
    // getters and setters
}

application.properties:

myapp.name=DemoApp
myapp.timeout=30

這樣 MyAppConfig 會(huì)自動(dòng)綁定配置值。

?? 小結(jié)

  • Environment 是配置的“中央倉庫”。
  • 配置源加載是分階段進(jìn)行的,且有明確的優(yōu)先級(jí)。
  • 命令行參數(shù)幾乎總是能覆蓋所有配置文件值。
  • @Value 適合單個(gè)配置值,@ConfigurationProperties 適合批量綁定。

4. ApplicationContext的創(chuàng)建與刷新

4.1 ApplicationContext 的類型選擇

SpringApplication.createApplicationContext() 中,會(huì)根據(jù) WebApplicationType 選擇不同的 ApplicationContext 實(shí)現(xiàn):

應(yīng)用類型ApplicationContext 實(shí)現(xiàn)類
SERVLETAnnotationConfigServletWebServerApplicationContext
REACTIVEAnnotationConfigReactiveWebServerApplicationContext
NONEAnnotationConfigApplicationContext

源碼(簡化)

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(
                        "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
                case REACTIVE:
                    contextClass = Class.forName(
                        "org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                    break;
                default:
                    contextClass = Class.forName(
                        "org.springframework.context.annotation.AnnotationConfigApplicationContext");
            }
        } catch (ClassNotFoundException ex) {
            throw new IllegalStateException("Unable to create ApplicationContext", ex);
        }
    }
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

重點(diǎn)

  • SERVLET 類型不僅是 IoC 容器,還會(huì)管理內(nèi)嵌的 Servlet Web 服務(wù)器(Tomcat/Jetty/Undertow)。
  • REACTIVE 類型則會(huì)啟動(dòng) Netty 作為反應(yīng)式 Web 服務(wù)器。
  • NONE 類型適用于純后端任務(wù)(無Web功能)。

4.2 refreshContext() 核心邏輯解析

refreshContext() 會(huì)調(diào)用 Spring Framework 的 AbstractApplicationContext.refresh(),這是 IoC 容器生命周期的核心方法。

簡化執(zhí)行步驟(以 Servlet 應(yīng)用為例):

  • 準(zhǔn)備刷新上下文
    • 初始化屬性源(PropertySources)
    • 驗(yàn)證必需的屬性是否存在
  • 獲取并準(zhǔn)備 BeanFactory
    • 創(chuàng)建 DefaultListableBeanFactory
  • 執(zhí)行 BeanFactoryPostProcessor
    • 在 Bean 定義加載后、實(shí)例化前執(zhí)行
  • 注冊(cè) BeanPostProcessor
    • 在 Bean 實(shí)例化前后進(jìn)行增強(qiáng)(如 @Autowired 注入、AOP 代理)
  • 初始化消息源(MessageSource)
    • 用于國際化
  • 初始化事件廣播器(ApplicationEventMulticaster)
  • 創(chuàng)建內(nèi)嵌 Web 服務(wù)器(ServletWebServerFactory)并啟動(dòng)
  • 實(shí)例化剩余的單例 Bean
  • 完成刷新
    • 發(fā)布 ContextRefreshedEvent

4.3 BeanFactoryPostProcessor 與 BeanPostProcessor 執(zhí)行順序

很多擴(kuò)展功能(比如 MyBatis、Spring Cloud)都是依賴這兩個(gè)接口來修改 Bean 定義或 Bean 實(shí)例的。

執(zhí)行順序

  • BeanFactoryPostProcessor
    • 作用:修改 Bean 定義元數(shù)據(jù)(BeanDefinition
    • 運(yùn)行時(shí)機(jī):Bean 實(shí)例化 之前
    • 常見實(shí)現(xiàn):ConfigurationClassPostProcessor(處理 @Configuration、@Bean)
  • BeanPostProcessor
    • 作用:增強(qiáng) Bean 實(shí)例(代理、依賴注入等)
    • 運(yùn)行時(shí)機(jī):Bean 實(shí)例化 前后
    • 常見實(shí)現(xiàn):AutowiredAnnotationBeanPostProcessor(處理 @Autowired)、AopProxyCreator

示例:自定義 BeanPostProcessor

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if (beanName.equals("myService")) {
            System.out.println("Before init: " + beanName);
        }
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (beanName.equals("myService")) {
            System.out.println("After init: " + beanName);
        }
        return bean;
    }
}

4.4 BootstrapContext 的作用

在 Spring Boot 2.4 之后引入 BootstrapContext,它是應(yīng)用啟動(dòng)早期的一個(gè)輕量級(jí)上下文,用于注冊(cè)啟動(dòng)前所需的組件,典型用途是:

  • 注冊(cè)配置加載器(Spring Cloud Config 使用)
  • 注冊(cè)早期的監(jiān)控或指標(biāo)收集組件

源碼片段

DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ApplicationEnvironmentPreparedEvent event =
        new ApplicationEnvironmentPreparedEvent(this, args, environment);
listeners.environmentPrepared(bootstrapContext, environment);

?? 小結(jié)

  • ApplicationContext 是整個(gè)應(yīng)用的核心容器,負(fù)責(zé) Bean 生命周期、事件、資源管理。
  • refresh() 是啟動(dòng)過程中 Bean 加載的核心方法。
  • BeanFactoryPostProcessor 改定義,BeanPostProcessor 改實(shí)例。
  • BootstrapContext 在早期階段提供了擴(kuò)展能力。

5. 自動(dòng)配置與條件化裝配

Spring Boot最大的亮點(diǎn)之一,就是它的自動(dòng)配置(Auto-Configuration)機(jī)制——你只需要引入依賴,不用手動(dòng)配置,相關(guān)的Bean就會(huì)自動(dòng)幫你注冊(cè)好。

這一章我們會(huì)拆開它的底層原理,逐步分析:

5.1 @EnableAutoConfiguration 原理

在Spring Boot應(yīng)用的啟動(dòng)類中,我們經(jīng)常會(huì)看到:

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

@SpringBootApplication 是一個(gè)組合注解,內(nèi)部包含了:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
                      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)}
)
public @interface SpringBootApplication {
    // ...
}

核心就是 @EnableAutoConfiguration。

源碼入口

@EnableAutoConfiguration 本身也只是一個(gè)注解,它通過 @Import 引入了 AutoConfigurationImportSelector

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    Class<?>[] exclude() default {};
    String[] excludeName() default {};
}

重點(diǎn)來了:

  • @Import 會(huì)把 AutoConfigurationImportSelector 這個(gè)類加入到容器啟動(dòng)過程中。
  • 這個(gè)類會(huì)掃描所有 META-INF/spring.factories 中聲明的自動(dòng)配置類。

5.2 SpringFactoriesLoader 與 META-INF/spring.factories

SpringFactoriesLoader 是一個(gè)幫助類,負(fù)責(zé)加載 META-INF/spring.factories 文件中定義的類名列表。

典型的 spring.factories 文件:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration

工作流程:

  • SpringFactoriesLoader.loadFactoryNames() 會(huì)掃描所有依賴包下的 META-INF/spring.factories 文件。
  • 讀取 key 為 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的配置值。
  • 把這些類(通常以 xxxAutoConfiguration 結(jié)尾)交給Spring容器去加載。

源碼關(guān)鍵點(diǎn)(SpringFactoriesLoader)

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    String factoryTypeName = factoryType.getName();
    return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
  • 這里的 factoryType 就是 EnableAutoConfiguration.class
  • 最終得到一個(gè)自動(dòng)配置類的全限定名列表

5.3 條件化注解(@ConditionalXXX)

自動(dòng)配置類并不是無條件生效的,它們會(huì)結(jié)合一系列條件注解判斷當(dāng)前環(huán)境是否滿足,再?zèng)Q定是否注冊(cè)Bean。

常見的條件注解:

注解作用
@ConditionalOnClass當(dāng)類路徑存在指定類時(shí)生效
@ConditionalOnMissingClass當(dāng)類路徑不存在指定類時(shí)生效
@ConditionalOnBean當(dāng)容器中存在指定Bean時(shí)生效
@ConditionalOnMissingBean當(dāng)容器中不存在指定Bean時(shí)生效
@ConditionalOnProperty當(dāng)配置文件中存在某個(gè)屬性并且值匹配時(shí)生效
@ConditionalOnWebApplication當(dāng)應(yīng)用是Web類型時(shí)生效
@ConditionalOnNotWebApplication當(dāng)應(yīng)用不是Web類型時(shí)生效
@ConditionalOnExpression根據(jù)SpEL表達(dá)式結(jié)果決定是否生效

例子(JacksonAutoConfiguration):

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ObjectMapper.class)
@EnableConfigurationProperties(JacksonProperties.class)
public class JacksonAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        return builder.createXmlMapper(false).build();
    }
}

解釋:

  • 如果Classpath中有 ObjectMapper 類(Jackson庫),則配置生效。
  • 如果容器中沒有 ObjectMapper,則自動(dòng)注冊(cè)一個(gè)。

5.4 自定義自動(dòng)配置類實(shí)戰(zhàn)

假設(shè)我們想在Spring Boot啟動(dòng)時(shí),自動(dòng)配置一個(gè) HelloService

1. 編寫服務(wù)類

public class HelloService {
    public String sayHello(String name) {
        return "Hello, " + name;
    }
}

2. 編寫自動(dòng)配置類

@Configuration
@ConditionalOnClass(HelloService.class)
public class HelloServiceAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public HelloService helloService() {
        return new HelloService();
    }
}

3. 配置 META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.demo.config.HelloServiceAutoConfiguration

4. 引入依賴后直接使用

@RestController
public class HelloController {
    @Autowired
    private HelloService helloService;
    @GetMapping("/hello")
    public String hello(String name) {
        return helloService.sayHello(name);
    }
}

無需額外配置,訪問 /hello?name=Boot 即可看到自動(dòng)配置效果。

5.5 條件注解(@ConditionalXXX)的源碼執(zhí)行流程

Spring Boot 的自動(dòng)配置類之所以能“按需生效”,核心就是依賴 Spring Framework 提供的 條件化裝配機(jī)制,也就是 @Conditional。

5.5.1 條件注解的繼承關(guān)系

所有 @ConditionalOnXxx 注解,最終都是 @Conditional 的語法糖。

舉個(gè)例子:

@ConditionalOnClass(ObjectMapper.class)

展開看源碼:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
    Class<?>[] value() default {};
    String[] name() default {};
}

可以看到:

  • 它其實(shí)就是 @Conditional,只不過指定了一個(gè) Condition 實(shí)現(xiàn)類:OnClassCondition。
  • 也就是說,@ConditionalOnClass -> OnClassCondition -> 判斷classpath是否存在指定類。

5.5.2 條件評(píng)估流程

條件注解是在 Spring 容器啟動(dòng)階段,由 ConfigurationClassPostProcessor 解析 @Configuration 類時(shí)進(jìn)行評(píng)估的。

流程大致是:

  • 掃描到自動(dòng)配置類
    • ConfigurationClassParser 解析自動(dòng)配置類上的注解。
  • 遇到 @Conditional
    • 調(diào)用 ConditionEvaluator.shouldSkip() 方法。
  • 找到對(duì)應(yīng) Condition 實(shí)現(xiàn)類
    • 比如 OnClassCondition,會(huì)去執(zhí)行 matches() 方法。
  • 返回 true/false
    • true 表示條件滿足 -> 該配置類或方法會(huì)注冊(cè)到容器
    • false 表示條件不滿足 -> 直接跳過

源碼片段(ConditionEvaluator)

public boolean shouldSkip(AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
    if (metadata.isAnnotated(Conditional.class.getName())) {
        List<Condition> conditions = getConditionClasses(metadata);
        for (Condition condition : conditions) {
            if (!condition.matches(context, metadata)) {
                return true; // 跳過
            }
        }
    }
    return false;
}

重點(diǎn):

  • matches() 方法是判斷條件是否成立的地方。
  • 每個(gè) @ConditionalOnXxx 注解都有自己的 Condition 實(shí)現(xiàn)類。

5.5.3 常見 Condition 實(shí)現(xiàn)類

條件注解對(duì)應(yīng) Condition 類作用
@ConditionalOnClassOnClassCondition檢查類路徑是否存在指定類
@ConditionalOnMissingClassOnClassCondition檢查類路徑是否不存在指定類
@ConditionalOnBeanOnBeanCondition檢查容器中是否存在指定 Bean
@ConditionalOnMissingBeanOnBeanCondition檢查容器中是否不存在指定 Bean
@ConditionalOnPropertyOnPropertyCondition檢查配置文件中屬性是否滿足
@ConditionalOnWebApplicationOnWebApplicationCondition檢查應(yīng)用是否是 Web 環(huán)境
@ConditionalOnExpressionOnExpressionCondition執(zhí)行 SpEL 表達(dá)式并判斷結(jié)果

5.5.4 執(zhí)行順序與調(diào)試技巧

  • 條件判斷會(huì)在 BeanDefinition 注冊(cè)階段執(zhí)行,而不是Bean實(shí)例化階段。
  • 你可以在 Condition.matches() 方法里打斷點(diǎn),啟動(dòng)項(xiàng)目,就能看到哪些條件返回 false,從而排查自動(dòng)配置沒生效的原因。
  • Spring Boot 提供了一個(gè) --debug 啟動(dòng)參數(shù),可以打印出條件評(píng)估報(bào)告。

命令行啟動(dòng)

java -jar demo.jar --debug

部分輸出

=========================
CONDITIONS EVALUATION REPORT
=========================
Positive matches:
-----------------
   JacksonAutoConfiguration matched:
      - @ConditionalOnClass found required class 'com.fasterxml.jackson.databind.ObjectMapper' (OnClassCondition)
Negative matches:
-----------------
   DataSourceAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'javax.sql.DataSource' (OnClassCondition)

這樣你就能非常清楚地知道某個(gè)自動(dòng)配置類為什么沒生效

5.6 自動(dòng)配置的優(yōu)先級(jí)與覆蓋規(guī)則

Spring Boot 設(shè)計(jì)的自動(dòng)配置是低優(yōu)先級(jí)的,這樣開發(fā)者可以隨時(shí)覆蓋默認(rèn)配置。

5.6.1 自動(dòng)配置的核心原則

  • 用戶優(yōu)先(開發(fā)者自己配置的 Bean 優(yōu)先于 Spring Boot 提供的 Bean)
  • 條件觸發(fā)(只有在條件成立時(shí),自動(dòng)配置才會(huì)生效)
  • 可覆蓋可禁用(你可以通過配置文件或注解控制自動(dòng)配置是否啟用)

5.6.2 自動(dòng)配置的低優(yōu)先級(jí)實(shí)現(xiàn)方式

1.@ConditionalOnMissingBean
  • 大多數(shù)自動(dòng)配置類在注冊(cè) Bean 時(shí)都會(huì)加上這個(gè)條件。
  • 表示:如果容器中已經(jīng)有這個(gè) Bean,就不再創(chuàng)建默認(rèn)的 Bean

示例:

@Bean
@ConditionalOnMissingBean
public ObjectMapper objectMapper() {
    return new ObjectMapper();
}

意思是:

  • 如果你自己在配置類里聲明了 ObjectMapper Bean,那么 Boot 的這個(gè)方法不會(huì)執(zhí)行。
2.@AutoConfigureBefore/@AutoConfigureAfter
  • 用來指定自動(dòng)配置類之間的順序
  • 比如:
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class MyCustomJsonConfig { ... }

這樣你的配置會(huì)在 JacksonAutoConfiguration 之前執(zhí)行。

3.@Primary
  • 如果你想讓多個(gè)同類型 Bean 中某一個(gè)優(yōu)先被注入,可以加上 @Primary。
  • 這不是自動(dòng)配置特有的,但常用于覆蓋默認(rèn) Bean。
4.spring.main.allow-bean-definition-overriding
  • Spring Boot 2.1 以后默認(rèn)不允許 Bean 覆蓋,如果你聲明了和默認(rèn)配置同名的 Bean 會(huì)報(bào)錯(cuò)。
  • 解決辦法:
spring:
  main:
    allow-bean-definition-overriding: true

這樣你的 Bean 會(huì)覆蓋默認(rèn) Bean。

5.6.3 禁用某個(gè)自動(dòng)配置

有三種常用方式:

方式 1:@SpringBootApplication(exclude = ...)
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class MyApp {}
方式 2:配置文件
spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
方式 3:META-INF/spring.factories
  • 這種是你自己寫 starter 時(shí)用的,普通項(xiàng)目一般不直接操作。

5.6.4 調(diào)試 Bean 覆蓋問題

  • 啟動(dòng)加 --debug 看條件評(píng)估報(bào)告。
  • 使用 ApplicationContext 打印所有 Bean:
Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println);

如果報(bào) BeanDefinitionOverrideException,先確認(rèn)是否是自己命名沖突,必要時(shí)允許覆蓋。

6. Spring Boot啟動(dòng)流程的擴(kuò)展點(diǎn)

Spring Boot的設(shè)計(jì)理念之一是高度的可擴(kuò)展性。在啟動(dòng)過程中,Spring Boot提供了豐富的擴(kuò)展點(diǎn),允許開發(fā)者在不同階段插入自定義邏輯,滿足多樣化的業(yè)務(wù)需求。這一章將詳細(xì)介紹Spring Boot啟動(dòng)流程中常用的擴(kuò)展點(diǎn),包括SpringApplicationRunListenerApplicationListener以及SpringApplicationBuilder的鏈?zhǔn)絾?dòng)配置。

6.1 SpringApplicationRunListener —— 啟動(dòng)事件監(jiān)聽器

6.1.1 作用與觸發(fā)時(shí)機(jī)

SpringApplicationRunListener接口用于監(jiān)聽Spring Boot啟動(dòng)流程的各個(gè)關(guān)鍵階段。它的核心目的是在啟動(dòng)流程的不同時(shí)間點(diǎn)觸發(fā)回調(diào),幫助開發(fā)者插入自定義操作或日志打印等輔助功能。

Spring Boot啟動(dòng)時(shí)會(huì)依次調(diào)用SpringApplicationRunListener中的如下事件方法:

  • starting():啟動(dòng)初始化,Spring Boot啟動(dòng)的第一個(gè)階段。
  • environmentPrepared(ConfigurableEnvironment environment):環(huán)境準(zhǔn)備完成,配置已加載。
  • contextPrepared(ConfigurableApplicationContext context)ApplicationContext創(chuàng)建完成但尚未刷新。
  • contextLoaded(ConfigurableApplicationContext context)ApplicationContext加載完成。
  • started(ConfigurableApplicationContext context)ApplicationContext刷新完成。
  • running(ConfigurableApplicationContext context):應(yīng)用準(zhǔn)備就緒,進(jìn)入運(yùn)行狀態(tài)。
  • failed(ConfigurableApplicationContext context, Throwable exception):啟動(dòng)失敗回調(diào)。

6.1.2 Spring Boot內(nèi)部實(shí)現(xiàn)及自動(dòng)加載

Spring Boot通過META-INF/spring.factories文件自動(dòng)加載所有注冊(cè)的SpringApplicationRunListener實(shí)現(xiàn)。常見的內(nèi)置實(shí)現(xiàn)包括:

  • EventPublishingRunListener:負(fù)責(zé)將啟動(dòng)事件發(fā)布到Spring事件機(jī)制。
  • ClasspathLoggingApplicationListener:啟動(dòng)時(shí)打印類路徑信息。
  • StartupInfoLogger:打印啟動(dòng)信息統(tǒng)計(jì)。

自動(dòng)加載示例(spring.factories文件):

org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener

6.1.3 自定義 SpringApplicationRunListener

開發(fā)者可以通過實(shí)現(xiàn)SpringApplicationRunListener接口來自定義啟動(dòng)事件監(jiān)聽器。實(shí)現(xiàn)步驟:

  • 實(shí)現(xiàn)接口并提供帶SpringApplicationString[] args構(gòu)造函數(shù)。
  • META-INF/spring.factories注冊(cè)監(jiān)聽器類。

示例代碼:

public class MyRunListener implements SpringApplicationRunListener {
    public MyRunListener(SpringApplication app, String[] args) {
        // 構(gòu)造器,必須包含這兩個(gè)參數(shù)
    }
    @Override
    public void starting() {
        System.out.println("應(yīng)用開始啟動(dòng)");
    }
    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        System.out.println("環(huán)境已準(zhǔn)備好");
    }
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("上下文已準(zhǔn)備好");
    }
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("上下文已加載");
    }
    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("應(yīng)用已啟動(dòng)");
    }
    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("應(yīng)用正在運(yùn)行");
    }
    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("應(yīng)用啟動(dòng)失敗,異常信息:" + exception.getMessage());
    }
}

注冊(cè)監(jiān)聽器:

org.springframework.boot.SpringApplicationRunListener=com.example.MyRunListener

6.2 ApplicationListener —— Spring事件監(jiān)聽器

6.2.1 作用與應(yīng)用場(chǎng)景

ApplicationListener是Spring框架的核心事件監(jiān)聽接口,支持監(jiān)聽包括啟動(dòng)事件在內(nèi)的所有Spring事件。它基于Spring的事件發(fā)布機(jī)制,允許開發(fā)者對(duì)特定事件做出響應(yīng)。

相比SpringApplicationRunListener,ApplicationListener更通用,不僅限于啟動(dòng)階段事件,還可監(jiān)聽?wèi)?yīng)用運(yùn)行過程中的各種事件。

6.2.2 常見啟動(dòng)事件類型

事件類觸發(fā)時(shí)機(jī)
ApplicationStartingEventSpring Boot啟動(dòng)最開始時(shí)
ApplicationEnvironmentPreparedEvent環(huán)境準(zhǔn)備完成時(shí)
ApplicationPreparedEventApplicationContext創(chuàng)建完畢,準(zhǔn)備刷新
ApplicationStartedEventApplicationContext刷新成功
ApplicationReadyEvent應(yīng)用啟動(dòng)完成,準(zhǔn)備接收請(qǐng)求
ApplicationFailedEvent應(yīng)用啟動(dòng)失敗

6.2.3 自定義ApplicationListener示例

@Component
public class MyReadyListener implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        System.out.println("應(yīng)用已準(zhǔn)備就緒,執(zhí)行自定義初始化操作...");
        // 例如啟動(dòng)緩存預(yù)熱、消息監(jiān)聽器等
    }
}

6.3 SpringApplicationBuilder —— 鏈?zhǔn)絾?dòng)配置工具

6.3.1 設(shè)計(jì)理念與優(yōu)勢(shì)

SpringApplicationBuilder是構(gòu)建SpringApplication實(shí)例的鏈?zhǔn)綐?gòu)建器,支持更靈活、優(yōu)雅的啟動(dòng)配置,適合復(fù)雜啟動(dòng)場(chǎng)景。

使用SpringApplicationBuilder,可以逐步疊加各種配置,如初始化器、監(jiān)聽器、激活Profile等,并最后調(diào)用run()方法啟動(dòng)應(yīng)用。

6.3.2 常用API與示例

  • sources(Class<?>... sources):設(shè)置主配置類或額外配置類。
  • initializers(ApplicationContextInitializer<?>... initializers):添加上下文初始化器。
  • listeners(ApplicationListener<?>... listeners):添加事件監(jiān)聽器。
  • profiles(String... profiles):激活指定環(huán)境。
  • run(String... args):啟動(dòng)應(yīng)用。

示例:

new SpringApplicationBuilder()
    .sources(MyApplication.class)
    .initializers(new MyContextInitializer())
    .listeners(new MyReadyListener())
    .profiles("dev")
    .run(args);

6.3.3 自定義ApplicationContextInitializer示例

public class MyContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("ApplicationContext初始化邏輯...");
        // 可以動(dòng)態(tài)注冊(cè)Bean、修改環(huán)境變量等
    }
}

6.4 小結(jié)

  • Spring Boot啟動(dòng)流程通過SpringApplicationRunListener提供了豐富的啟動(dòng)階段監(jiān)聽能力,適合執(zhí)行啟動(dòng)監(jiān)控、日志收集、資源準(zhǔn)備等任務(wù)。
  • ApplicationListener基于Spring事件機(jī)制,支持對(duì)啟動(dòng)事件及其他業(yè)務(wù)事件的監(jiān)聽,更加通用。
  • SpringApplicationBuilder是鏈?zhǔn)綐?gòu)建啟動(dòng)參數(shù)的工具,極大提升了啟動(dòng)配置的靈活性和可維護(hù)性。

通過掌握這幾個(gè)核心擴(kuò)展點(diǎn),開發(fā)者可以對(duì)Spring Boot啟動(dòng)流程進(jìn)行高度自定義,滿足各種復(fù)雜的啟動(dòng)需求,提升應(yīng)用的健壯性和擴(kuò)展能力。

7. Spring Boot啟動(dòng)性能優(yōu)化

隨著企業(yè)級(jí)應(yīng)用復(fù)雜度的提升,Spring Boot應(yīng)用的啟動(dòng)時(shí)間成為一個(gè)重要考量指標(biāo)。快速啟動(dòng)不僅提升開發(fā)效率,還能改善云環(huán)境中的彈性擴(kuò)縮容體驗(yàn)。此章將圍繞啟動(dòng)性能展開,講解啟動(dòng)耗時(shí)分析方法、常見瓶頸,以及針對(duì)性的優(yōu)化策略。

7.1 啟動(dòng)耗時(shí)分析:利用StopWatch

7.1.1 StopWatch在Spring Boot中的應(yīng)用

SpringApplication.run()方法中,Spring Boot通過org.springframework.util.StopWatch來度量啟動(dòng)各個(gè)階段的耗時(shí),幫助開發(fā)者定位瓶頸。

簡化代碼片段(摘自SpringApplication.run()):

StopWatch stopWatch = new StopWatch();
stopWatch.start("SpringApplication啟動(dòng)");
// 啟動(dòng)流程中的重要階段代碼...
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());

StopWatch會(huì)輸出類似如下的階段耗時(shí)報(bào)告:

StopWatch '': running time = 12345 ns
---------------------------------------------
ns         %     Task name
---------------------------------------------
5000000  40%   SpringApplication啟動(dòng)
7500000  60%   ApplicationContext刷新

7.1.2 使用啟動(dòng)日志和--debug參數(shù)定位耗時(shí)

Spring Boot支持通過命令行參數(shù)--debug開啟詳細(xì)日志,打印啟動(dòng)過程中的細(xì)節(jié)信息,便于發(fā)現(xiàn)耗時(shí)較長的組件或階段。

java -jar myapp.jar --debug

日志中會(huì)包含大量有用信息,如自動(dòng)配置條件匹配、Bean創(chuàng)建時(shí)間等。

7.2 主要啟動(dòng)性能瓶頸分析

  • 自動(dòng)配置掃描與條件判斷:復(fù)雜的@Conditional注解邏輯,條件不匹配時(shí)仍需執(zhí)行判斷,影響啟動(dòng)速度。
  • Bean實(shí)例化和依賴注入:大量單例Bean的創(chuàng)建、復(fù)雜依賴關(guān)系的解析耗時(shí)較長。
  • 環(huán)境變量和配置加載:讀取多層配置文件和系統(tǒng)屬性,尤其是網(wǎng)絡(luò)配置(如遠(yuǎn)程配置中心)可能阻塞啟動(dòng)。
  • 類路徑掃描與組件掃描:掃描大量包及類時(shí)會(huì)增加啟動(dòng)負(fù)擔(dān)。
  • 嵌入式容器啟動(dòng):內(nèi)嵌Tomcat、Jetty或Undertow啟動(dòng)耗時(shí)不可忽視。

7.3 啟動(dòng)性能優(yōu)化策略

7.3.1 使用@Lazy延遲加載Bean

通過給不必要立即加載的Bean添加@Lazy注解,Spring容器會(huì)延遲初始化,減少啟動(dòng)時(shí)的Bean加載壓力。

示例:

@Configuration
public class MyConfig {
    @Bean
    @Lazy
    public HeavyService heavyService() {
        return new HeavyService();
    }
}

7.3.2 精準(zhǔn)配置@ComponentScan掃描范圍

縮小@ComponentScan的掃描范圍,避免掃描無關(guān)包,減少類路徑掃描時(shí)間。

@SpringBootApplication(scanBasePackages = "com.example.myapp.service")
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

7.3.3 禁用不必要的自動(dòng)配置

通過@SpringBootApplication(exclude = {AutoConfigurationClass.class})排除不需要的自動(dòng)配置類,避免無用配置初始化。

示例:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MyApplication { ... }

7.3.4 自定義自動(dòng)配置條件減少啟動(dòng)判斷

簡化自動(dòng)配置中的@Conditional注解判斷邏輯,避免復(fù)雜條件鏈。

7.3.5 采用Spring Boot Layered JAR優(yōu)化啟動(dòng)

Spring Boot 2.3+支持分層Jar結(jié)構(gòu),將應(yīng)用、依賴、啟動(dòng)器分開打包,有助于加速Docker鏡像啟動(dòng)。

7.4 實(shí)踐示例:啟動(dòng)時(shí)間統(tǒng)計(jì)與延遲加載

@SpringBootApplication
public class PerformanceApp {
    public static void main(String[] args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("啟動(dòng)應(yīng)用");
        SpringApplication app = new SpringApplication(PerformanceApp.class);
        app.run(args);
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
    }
    @Bean
    @Lazy
    public ExpensiveBean expensiveBean() {
        System.out.println("初始化ExpensiveBean...");
        return new ExpensiveBean();
    }
}

運(yùn)行該程序,可以看到啟動(dòng)階段時(shí)間統(tǒng)計(jì),并且expensiveBean只有在首次調(diào)用時(shí)才初始化。

7.5 總結(jié)

  • 通過StopWatch--debug日志,能有效定位啟動(dòng)耗時(shí)階段。
  • 延遲加載、精準(zhǔn)掃描、排除無用自動(dòng)配置是主要優(yōu)化手段。
  • 優(yōu)化啟動(dòng)性能有助于提升開發(fā)效率、加快部署速度、降低云環(huán)境資源消耗。

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

相關(guān)文章

  • SpringBoot整合Spring?Boot?Admin實(shí)現(xiàn)服務(wù)監(jiān)控的方法

    SpringBoot整合Spring?Boot?Admin實(shí)現(xiàn)服務(wù)監(jiān)控的方法

    這篇文章主要介紹了SpringBoot整合Spring?Boot?Admin實(shí)現(xiàn)服務(wù)監(jiān)控,內(nèi)容包括Server端服務(wù)開發(fā),Client端服務(wù)開發(fā)其中Spring Boot Admin還可以對(duì)其監(jiān)控的服務(wù)提供告警功能,如服務(wù)宕機(jī)時(shí),可以及時(shí)以郵件方式通知運(yùn)維人員,感興趣的朋友跟隨小編一起看看吧
    2022-03-03
  • SpringCloud Zuul和Gateway的實(shí)例代碼(搭建方式)

    SpringCloud Zuul和Gateway的實(shí)例代碼(搭建方式)

    本文主要介紹了SpringCloudZuul和SpringCloudGateway的簡單示例,SpringCloudGateway是推薦使用的API網(wǎng)關(guān)解決方案,基于SpringFramework5和ProjectReactor構(gòu)建,具有更高的性能和吞吐量
    2025-02-02
  • jdk自帶線程池實(shí)例詳解

    jdk自帶線程池實(shí)例詳解

    在最近做的一個(gè)項(xiàng)目中,需要大量的使用到多線程和線程池,下面就java自帶的線程池和大家一起分享
    2018-02-02
  • 通過實(shí)例分析java多態(tài)

    通過實(shí)例分析java多態(tài)

    這篇文章主要介紹了通過實(shí)例分析java多態(tài),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Java+opencv3.2.0實(shí)現(xiàn)模板匹配

    Java+opencv3.2.0實(shí)現(xiàn)模板匹配

    這篇文章主要為大家詳細(xì)介紹了Java+opencv3.2.0實(shí)現(xiàn)模板匹配的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • Java中的Fork/Join框架使用詳解

    Java中的Fork/Join框架使用詳解

    這篇文章主要介紹了Java中的Fork/Join框架使用詳解,Fork/Join?框架:就是在必要的情況下,將一個(gè)大任務(wù),進(jìn)行<BR>拆分(fork)成若干個(gè)小任務(wù)(拆到不可再拆時(shí)),再將一個(gè)個(gè)<BR>的小任務(wù)運(yùn)算的結(jié)果進(jìn)行?join?匯總,需要的朋友可以參考下
    2024-01-01
  • Spring BeanPostProcessor源碼示例解析

    Spring BeanPostProcessor源碼示例解析

    這篇文章主要為大家介紹了Spring BeanPostProcessor源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • java獲取新insert數(shù)據(jù)自增id的實(shí)現(xiàn)方法

    java獲取新insert數(shù)據(jù)自增id的實(shí)現(xiàn)方法

    這篇文章主要介紹了java獲取新insert數(shù)據(jù)自增id的實(shí)現(xiàn)方法,在具體生成id的時(shí)候,我們的操作順序一般是:先在主表中插入記錄,然后獲得自動(dòng)生成的id,以它為基礎(chǔ)插入從表的記錄,需要的朋友可以參考下
    2019-06-06
  • Maven在Java8下如何忽略Javadoc的編譯錯(cuò)誤詳解

    Maven在Java8下如何忽略Javadoc的編譯錯(cuò)誤詳解

    這篇文章主要給大家介紹了關(guān)于Maven在Java8下如何忽略Javadoc的編譯錯(cuò)誤的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • idea使用war以及war exploded的區(qū)別說明

    idea使用war以及war exploded的區(qū)別說明

    本文詳細(xì)解析了war與warexploded兩種部署方式的差異及步驟,war方式是先打包成war包,再部署到服務(wù)器上;warexploded方式是直接把文件夾、class文件等移到Tomcat上部署,支持熱部署,開發(fā)時(shí)常用,文章分別列出了warexploded模式和war包形式的具體操作步驟
    2024-10-10

最新評(píng)論

玛纳斯县| 鲜城| 抚松县| 玉屏| 朝阳县| 阳东县| 嘉义县| 措美县| 安福县| 萝北县| 南溪县| 青龙| 剑阁县| 青州市| 宁蒗| 英吉沙县| 绩溪县| 连江县| 平乐县| 雅安市| 沐川县| 马尔康县| 福清市| 通化市| 江源县| 巩留县| 定州市| 新沂市| 吉安县| 原平市| 分宜县| 长治市| 灯塔市| 海原县| 林周县| 大英县| 富裕县| 长宁区| 石泉县| 广丰县| 库车县|