SpringBoot项目启动速度深度优化指南

 更新时间:2026年05月15日 09:42:20   作者:河阿里  
本文介绍了Spring Boot 2.7.x~3.2.x的启动优化方法,从依赖优化、自动配置优化、Bean扫描与注册优化、懒加载优化、初始化逻辑优化、JVM调优等多方面进行详细阐述,通过依赖优化、禁用不必要的自动配置、缩小Bean扫描范围、全局开启懒加载等策略,需要的朋友可以参考下

适用版本:SpringBoot 2.7.x ~ 3.2.x
调优目标:将中小型应用启动时间从10-30秒优化至3-8秒,大型应用从60秒以上优化至20秒以内

一、问题分析

SpringBoot 凭借"约定大于配置"的理念极大提升了开发效率,但随着项目规模扩大和依赖增多,启动速度会急剧下降。慢启动不仅影响开发体验(热部署等待时间长),还会降低生产环境的弹性伸缩能力(K8s Pod 启动超时、滚动更新缓慢)。

1.1 SpringBoot 核心启动流程(耗时分布)

一个典型的 SpringBoot 应用启动分为以下5个阶段,各阶段耗时占比大致如下:

阶段耗时占比核心操作
JVM启动与类加载20%~30%JVM初始化、字节码加载、验证、准备、解析
Spring上下文构建40%~60%Bean扫描、自动配置、Bean定义注册
Bean实例化与依赖注入15%~25%单例Bean创建、依赖注入、AOP代理生成
应用初始化5%~15%CommandLineRunner、ApplicationRunner执行
Web服务器启动5%~10%Tomcat/Jetty/Undertow初始化、端口绑定

1.2 启动速度诊断工具

在进行调优前,必须先通过工具定位瓶颈,避免盲目优化:

1.2.1 内置启动分析器(SpringBoot 2.4+)

# 开启启动时间记录
spring.main.startup-time=true
# 输出详细的Bean创建耗时
logging.level.org.springframework.beans.factory.support.DefaultListableBeanFactory=DEBUG

1.2.2 Spring Boot Actuator 端点

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management.endpoints.web.exposure.include=startup
management.endpoint.startup.enabled=true

访问 http://localhost:8080/actuator/startup 获取结构化的启动数据。

二、调优策略

2.1 依赖优化(最直接有效的优化手段)

2.1.1 移除未使用的依赖

SpringBoot 自动配置会根据依赖存在与否激活相应功能,多余的依赖会导致大量不必要的自动配置执行。

操作步骤

  1. 使用 mvn dependency:analyze 分析未使用的依赖
  2. 移除 spring-boot-starter-* 中不需要的传递依赖
  3. 避免引入"全家桶"式依赖(如 spring-cloud-starter

示例

<!-- 错误:引入了不必要的web依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 正确:只保留需要的依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!-- 排除不需要的传递依赖 -->
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

2.1.2 优化依赖版本与范围

  • 使用 spring-boot-dependencies 管理依赖版本,避免版本冲突
  • 将测试依赖的 scope 设置为 test
  • 对于仅在编译时需要的依赖,使用 provided scope

2.1.3 替换重量级依赖

重量级依赖轻量级替代方案启动时间提升
TomcatUndertow/Jetty10%~20%
Hibernate ValidatorSpring Validation5%~10%
JacksonFastjson2(谨慎使用)5%~15%
Spring Data JPAMyBatis-Plus/原生MyBatis20%~40%

2.2 自动配置优化

SpringBoot 的自动配置虽然方便,但会扫描大量条件注解,执行大量条件判断。

2.2.1 排除不需要的自动配置

@SpringBootApplication(
    exclude = {
        DataSourceAutoConfiguration.class,
        RedisAutoConfiguration.class,
        SecurityAutoConfiguration.class,
        ThymeleafAutoConfiguration.class,
        MailSenderAutoConfiguration.class
    }
)
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

技巧:通过 --debug 参数启动应用,查看所有自动配置的匹配情况:

java -jar app.jar --debug

2.2.2 禁用JMX支持(生产环境)

# 禁用JMX自动配置
spring.jmx.enabled=false
# 禁用端点JMX暴露
management.endpoints.jmx.exposure.exclude=*

效果:减少约5%~10%的启动时间。

2.2.3 禁用不必要的AOP自动配置

# 禁用Spring AOP自动代理(如果不使用AOP)
spring.aop.auto=false
# 禁用事务AOP(如果不使用声明式事务)
spring.transaction.auto=false

2.3 Bean扫描与注册优化

2.3.1 缩小Bean扫描范围

默认情况下,@SpringBootApplication 会扫描主类所在包及其子包下的所有类。如果项目结构复杂,扫描范围过大将严重影响启动速度。

优化方案

// 明确指定扫描的包,避免扫描无关目录
@SpringBootApplication(scanBasePackages = "com.company.project")
// 更精确:只扫描包含组件的包
@ComponentScan(basePackages = {
    "com.company.project.controller",
    "com.company.project.service",
    "com.company.project.mapper"
})

建议

  • 主类放在最顶层包下
  • 避免将无关的类放在扫描路径下
  • 不要使用 @ComponentScan("com.company") 扫描整个公司包

2.3.2 使用@Configuration替代@Component进行配置

@Configuration 类会被 CGLIB 代理,但在启动时处理更快,且能更好地控制Bean的创建顺序。

2.3.3 避免使用@Component注解在抽象类和接口上

抽象类和接口上的 @Component 注解会被Spring忽略,但会增加扫描时间。

2.4 懒加载优化

懒加载(Lazy Initialization)是指Bean在第一次被使用时才创建,而不是在应用启动时创建。这是提升启动速度最有效的手段之一。

2.4.1 全局开启懒加载(SpringBoot 2.2+)

# 全局开启懒加载
spring.main.lazy-initialization=true

注意事项

  • 全局懒加载会延迟所有Bean的创建,包括Web服务器、数据源等核心组件
  • 第一次请求的响应时间会变长
  • 某些依赖启动时初始化的功能可能会失效(如定时任务)

2.4.2 选择性懒加载(推荐)

// 对单个Bean使用懒加载
@Service
@Lazy
public class HeavyService {
    // 耗时的初始化操作
}

// 对配置类中的所有Bean使用懒加载
@Configuration
@Lazy
public class HeavyConfig {
    @Bean
    public HeavyBean heavyBean() {
        return new HeavyBean();
    }
}

2.4.3 排除关键Bean的懒加载

@Configuration
public class CriticalConfig {
    // 关键Bean不使用懒加载
    @Bean
    @Lazy(false)
    public DataSource dataSource() {
        return new HikariDataSource();
    }
}

2.5 初始化逻辑优化

2.5.1 优化@PostConstruct方法

@PostConstruct 方法会在Bean创建后立即执行,耗时的初始化操作会阻塞启动流程。

优化方案

// 错误:在@PostConstruct中执行耗时操作
@Service
public class BadService {
    @PostConstruct
    public void init() {
        // 耗时操作:加载大量数据、调用外部接口
        loadLargeData();
    }
}

// 正确:使用异步初始化
@Service
public class GoodService {
    @PostConstruct
    public void init() {
        CompletableFuture.runAsync(this::loadLargeData);
    }
    
    private void loadLargeData() {
        // 耗时操作
    }
}

2.5.2 优化CommandLineRunner和ApplicationRunner

  • 将非关键的初始化逻辑移至异步线程
  • 按优先级排序,先执行关键初始化
  • 避免在Runner中执行耗时操作
@Component
@Order(1) // 高优先级,先执行
public class CriticalRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        // 关键初始化逻辑
    }
}

@Component
@Order(2)
public class NonCriticalRunner implements CommandLineRunner {
    @Autowired
    private TaskExecutor taskExecutor;
    
    @Override
    public void run(String... args) throws Exception {
        taskExecutor.execute(() -> {
            // 非关键初始化逻辑
        });
    }
}

2.5.3 避免在Bean构造函数中执行耗时操作

构造函数中的代码会在Bean实例化时执行,会阻塞整个Bean的创建过程。

2.6 JVM调优

JVM参数对启动速度有显著影响,不同的JVM版本和垃圾回收器表现差异很大。

2.6.1 推荐JVM参数(Java 17+)

java -jar \
  -XX:+UseG1GC \
  -XX:MaxGCPauseMillis=200 \
  -XX:+TieredCompilation \
  -XX:TieredStopAtLevel=1 \
  -Xms512m \
  -Xmx1024m \
  -XX:+UseStringDeduplication \
  -XX:+DisableAttachMechanism \
  app.jar

关键参数说明

  • -XX:+TieredCompilation:开启分层编译,提升启动速度
  • -XX:TieredStopAtLevel=1:只使用C1编译器,大幅提升启动速度(适合开发环境)
  • -XX:+UseG1GC:G1垃圾回收器在启动速度和吞吐量之间取得平衡
  • -Xms-Xmx 设置为相同值,避免堆内存调整带来的开销

2.6.2 Java 11 vs Java 17 启动性能对比

Java 17 在启动速度上有显著提升,建议升级到最新的LTS版本:

  • 类加载速度提升约15%
  • JIT编译速度提升约20%
  • 内存占用减少约10%

2.7 开发环境专属优化

开发环境对启动速度的要求更高,以下优化仅适用于开发环境:

2.7.1 使用 Spring Boot DevTools

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

DevTools 提供了快速重启功能,只重新加载变化的类,重启时间通常在1-2秒。

2.7.2 禁用缓存和模板引擎缓存

# 禁用模板引擎缓存
spring.thymeleaf.cache=false
spring.freemarker.cache=false
# 禁用静态资源缓存
spring.web.resources.cache.period=0
# 禁用Hibernate二级缓存
spring.jpa.properties.hibernate.cache.use_second_level_cache=false

三、高级调优策略

3.1 使用 Spring Boot 3.x 与 GraalVM 原生镜像

Spring Boot 3.x 引入了对 GraalVM 原生镜像的支持,可以将应用编译成本地可执行文件,启动时间可降至毫秒级。

优势

  • 启动时间:从秒级降至毫秒级(通常<100ms)
  • 内存占用:减少约50%
  • 容器镜像大小:减少约70%

限制

  • 不支持动态类加载和反射(需要额外配置)
  • 编译时间长
  • 某些第三方库可能不兼容

3.2 模块化应用(Java 9+)

使用Java模块系统(JPMS)可以精确控制类加载,减少不必要的类加载:

module com.company.project {
    requires spring.boot;
    requires spring.boot.autoconfigure;
    requires spring.web;
    
    exports com.company.project;
}

3.3 拆分大型应用

对于超大型应用,最佳的优化方案是进行微服务拆分,将单一应用拆分为多个小型服务,每个服务的启动时间都会显著降低。

四、调优效果评估

4.1 调优前后对比(示例中小型应用)

调优阶段启动时间优化幅度
未调优18秒0%
依赖优化12秒33%
自动配置优化9秒25%
Bean扫描优化7秒22%
懒加载优化4秒43%
JVM调优3秒25%
总计3秒83%

4.2 调优效果验证方法

  1. 多次启动应用,取平均值(避免单次启动的偶然性)
  2. 对比调优前后的启动日志,查看各阶段耗时变化
  3. 使用压测工具验证应用性能是否受到影响
  4. 检查所有功能是否正常运行

五、调优注意事项

  1. 先诊断后优化:永远不要在没有定位瓶颈的情况下进行盲目优化
  2. 平衡启动速度与运行时性能:某些优化(如分层编译停止在Level 1)会降低运行时性能,仅适用于开发环境
  3. 避免过度优化:不要为了几毫秒的提升而牺牲代码的可读性和可维护性
  4. 持续监控:随着项目的迭代,启动速度可能会再次变慢,需要定期进行监控和优化
  5. 团队规范:制定团队开发规范,避免引入不必要的依赖和配置

以上就是SpringBoot项目启动速度深度优化指南的详细内容,更多关于SpringBoot项目启动速度优化的资料请关注脚本之家其它相关文章!

相关文章

  • 简单分析Java线程编程中ThreadLocal类的使用

    简单分析Java线程编程中ThreadLocal类的使用

    这篇文章主要介绍了Java线程编程中ThreadLocal类的使用,包括使用其对共享变量的操作的分析,需要的朋友可以参考下
    2015-12-12
  • 将SpringBoot的Jar注册成Windows服务的实现方法

    将SpringBoot的Jar注册成Windows服务的实现方法

    当前项目有个地图编辑器,后端用的是SpringBoot框架,外网刚好有一台空闲的Windows服务器就直接拿来用了,将Java程序部署成Windows服务可以用WinSW (Windows Service Wrapper)来实现,文中有详细的操作步骤,需要的朋友可以参考下
    2023-11-11
  • Springboot+SpringSecurity实现图片验证码登录的示例

    Springboot+SpringSecurity实现图片验证码登录的示例

    本文主要介绍了Springboot+SpringSecurity实现图片验证码登录的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • Spring Boot高效数据聚合之道深入讲解

    Spring Boot高效数据聚合之道深入讲解

    这篇文章主要给大家介绍了关于Spring Boot高效数据聚合之道的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-06-06
  • SpringMVC 参数绑定意义及实现过程解析

    SpringMVC 参数绑定意义及实现过程解析

    这篇文章主要介绍了SpringMVC 参数绑定意义及实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • 如何解决websocket开启多个页面访问同一个连接会失效的问题

    如何解决websocket开启多个页面访问同一个连接会失效的问题

    使用WebSocket时,若多个页面访问同一个WebSocket连接可能会导致连接失效,遇到这个问题时,可以通过在SpringBoot中使用@ServerEndpoint注解并添加@Component来解决,出现连接错误通常是因为WebSocket连接接收到的是一个GET请求
    2024-09-09
  • Mybatis动态SQL之if、choose、where、set、trim、foreach标记实例详解

    Mybatis动态SQL之if、choose、where、set、trim、foreach标记实例详解

    动态SQL就是动态的生成SQL。接下来通过本文给大家介绍Mybatis动态SQL之if、choose、where、set、trim、foreach标记实例详解的相关知识,感兴趣的朋友一起看看吧
    2016-09-09
  • Spring Cloud 使用 Resilience4j 实现服务熔断的方法

    Spring Cloud 使用 Resilience4j 实现服务熔断的方法

    服务熔断是为了保护我们的服务,比如当某个服务出现问题的时候,控制打向它的流量,让它有时间去恢复,或者限制一段时间只能有固定数量的请求打向这个服务,这篇文章主要介绍了Spring Cloud 使用 Resilience4j 实现服务熔断,需要的朋友可以参考下
    2022-12-12
  • Java基于面向对象实现一个战士小游戏

    Java基于面向对象实现一个战士小游戏

    这篇文章主要为大家详细介绍了Java如何基于面向对象实现一个战士小游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以动手尝试一下
    2022-07-07
  • JavaWeb ServletConfig作用及原理分析讲解

    JavaWeb ServletConfig作用及原理分析讲解

    ServletConfig对象,叫Servlet配置对象。主要用于加载配置文件的初始化参数。我们知道一个Web应用里面可以有多个servlet,如果现在有一份数据需要传给所有的servlet使用,那么我们就可以使用ServletContext对象了
    2022-10-10

最新评论