102人参与 • 2026-05-15 • Java
适用版本:springboot 2.7.x ~ 3.2.x
调优目标:将中小型应用启动时间从10-30秒优化至3-8秒,大型应用从60秒以上优化至20秒以内
springboot 凭借"约定大于配置"的理念极大提升了开发效率,但随着项目规模扩大和依赖增多,启动速度会急剧下降。慢启动不仅影响开发体验(热部署等待时间长),还会降低生产环境的弹性伸缩能力(k8s pod 启动超时、滚动更新缓慢)。
一个典型的 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初始化、端口绑定 |
在进行调优前,必须先通过工具定位瓶颈,避免盲目优化:
# 开启启动时间记录 spring.main.startup-time=true # 输出详细的bean创建耗时 logging.level.org.springframework.beans.factory.support.defaultlistablebeanfactory=debug
<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 获取结构化的启动数据。
springboot 自动配置会根据依赖存在与否激活相应功能,多余的依赖会导致大量不必要的自动配置执行。
操作步骤:
mvn dependency:analyze 分析未使用的依赖spring-boot-starter-* 中不需要的传递依赖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>spring-boot-dependencies 管理依赖版本,避免版本冲突testprovided scope| 重量级依赖 | 轻量级替代方案 | 启动时间提升 |
|---|---|---|
| tomcat | undertow/jetty | 10%~20% |
| hibernate validator | spring validation | 5%~10% |
| jackson | fastjson2(谨慎使用) | 5%~15% |
| spring data jpa | mybatis-plus/原生mybatis | 20%~40% |
springboot 的自动配置虽然方便,但会扫描大量条件注解,执行大量条件判断。
@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
# 禁用jmx自动配置 spring.jmx.enabled=false # 禁用端点jmx暴露 management.endpoints.jmx.exposure.exclude=*
效果:减少约5%~10%的启动时间。
# 禁用spring aop自动代理(如果不使用aop) spring.aop.auto=false # 禁用事务aop(如果不使用声明式事务) spring.transaction.auto=false
默认情况下,@springbootapplication 会扫描主类所在包及其子包下的所有类。如果项目结构复杂,扫描范围过大将严重影响启动速度。
优化方案:
// 明确指定扫描的包,避免扫描无关目录
@springbootapplication(scanbasepackages = "com.company.project")
// 更精确:只扫描包含组件的包
@componentscan(basepackages = {
"com.company.project.controller",
"com.company.project.service",
"com.company.project.mapper"
})
建议:
@componentscan("com.company") 扫描整个公司包@configuration 类会被 cglib 代理,但在启动时处理更快,且能更好地控制bean的创建顺序。
抽象类和接口上的 @component 注解会被spring忽略,但会增加扫描时间。
懒加载(lazy initialization)是指bean在第一次被使用时才创建,而不是在应用启动时创建。这是提升启动速度最有效的手段之一。
# 全局开启懒加载 spring.main.lazy-initialization=true
注意事项:
// 对单个bean使用懒加载
@service
@lazy
public class heavyservice {
// 耗时的初始化操作
}
// 对配置类中的所有bean使用懒加载
@configuration
@lazy
public class heavyconfig {
@bean
public heavybean heavybean() {
return new heavybean();
}
}
@configuration
public class criticalconfig {
// 关键bean不使用懒加载
@bean
@lazy(false)
public datasource datasource() {
return new hikaridatasource();
}
}
@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() {
// 耗时操作
}
}
@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(() -> {
// 非关键初始化逻辑
});
}
}
构造函数中的代码会在bean实例化时执行,会阻塞整个bean的创建过程。
jvm参数对启动速度有显著影响,不同的jvm版本和垃圾回收器表现差异很大。
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 设置为相同值,避免堆内存调整带来的开销java 17 在启动速度上有显著提升,建议升级到最新的lts版本:
开发环境对启动速度的要求更高,以下优化仅适用于开发环境:
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-devtools</artifactid>
<scope>runtime</scope>
<optional>true</optional>
</dependency>devtools 提供了快速重启功能,只重新加载变化的类,重启时间通常在1-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
spring boot 3.x 引入了对 graalvm 原生镜像的支持,可以将应用编译成本地可执行文件,启动时间可降至毫秒级。
优势:
限制:
使用java模块系统(jpms)可以精确控制类加载,减少不必要的类加载:
module com.company.project {
requires spring.boot;
requires spring.boot.autoconfigure;
requires spring.web;
exports com.company.project;
}
对于超大型应用,最佳的优化方案是进行微服务拆分,将单一应用拆分为多个小型服务,每个服务的启动时间都会显著降低。
| 调优阶段 | 启动时间 | 优化幅度 |
|---|---|---|
| 未调优 | 18秒 | 0% |
| 依赖优化 | 12秒 | 33% |
| 自动配置优化 | 9秒 | 25% |
| bean扫描优化 | 7秒 | 22% |
| 懒加载优化 | 4秒 | 43% |
| jvm调优 | 3秒 | 25% |
| 总计 | 3秒 | 83% |
以上就是springboot项目启动速度深度优化指南的详细内容,更多关于springboot项目启动速度优化的资料请关注代码网其它相关文章!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论