SpringBoot如何优化启动速度

1. 问题和期望2. 优化方式2.1 延迟初始化Bean2.2 创建扫描索引

3. 其他技巧4. 质的改变4.1 升级jdk174.2 升级SpringBoot3

1. 问题和期望

随着微服务和云原生时代的流行,SpringBoot应用也暴露出来了一些问题,其中有启动慢、应用内存占用多。

因为在云原生时代,我们更希望我们的应用:

启动速度快:因为我们的服务比较多,且当我们需要水平扩展的时候,希望这些服务能够在足够短的时间内完成启动,从而尽快的处理新增的请求。占用资源少:因为你的每个单个实例占用资源更少就意味着可以用同样的成本支持更多的访问请求。打包体积小:如果每个云原生应用体积比较大,我们进行推送和拉取镜像的时候,所耗费的时间也会比较大。

启动速度慢的原因是因为SpringBoot需要加载各种Bean导致的启动速度下降。

2. 优化方式

2.1 延迟初始化Bean

一般在SpringBoot中都拥有很多的耗时任务,比如数据库建立连接,初始线程池的创建等等,我们可以延迟这些操作的初始化,来达到优化启动速度的目的。SpringBoot2.2版本后引入spring.main.lazy-initialization属性,配置为true会将所有Bean延迟初始化。

spring:

main:

lazy-initialization: true

2.2 创建扫描索引

Spring5之后提供了spring-context-indexer功能,可以通过在编译时创建一个静态候选列表来提高大型应用程序的启动性能。 在项目中使用了@Indexed之后,编译打包的时候会在项目中自动生成META-INF/spring.components文件。

当Spring应用上下文执行ComponentScan扫描时,META-INF/spring.components将会被CandidateComponentsIndexLoader读取并加载,转换为CandidateComponentsIndex对象。

3. 其他技巧

减少@ComponentScan @SpringBootApplication扫描类时候的范围。关闭Spring Boot的JMX监控,设置spring.jmx.enabled=false。设置JVM参数 -noverify, 不对类进行验证。对非必要启动时加载的Bean,延迟加载。使用SpringBoot的全局懒加载。AOP切面尽量不使用注解方式,这会导致启动时扫描全部方法。关闭endpoint的一些监控功能。排除项目多余的依赖jar。swagger扫描接口时,指定只扫描某个路径下的类。Feign客户端接口的扫描缩小包扫描范围。

到这启动速度应该算是优化的比较极致了,但是内存占用依然是问题。

4. 质的改变

4.1 升级jdk17

内存占用多主要是内存占用后不会归还操作系统,这个正在逐步改善:

G1 JDK12及之后 已支持ZGC JDK13及之后 已支持

由于Java语言的特性及Spring Boot的一些实现方式,决定了即便是开启了G1/ZGC的去使用内存及时归还操作系统,Spring Boot的内存占用仍然远大于Golang这种编译型语言。

所以,Java想要解决云原生时代的问题,目前的方案基本都是基于GraalVM来的,不管是Quarkus(夸克)还是Micronaut都是。

那么,Spring Boot有没有类似的方案呢?:spring-graalvm-native

4.2 升级SpringBoot3

spring-graalvm-native是springboot3非常重大的一个特性,支持使用GraalVM将SpringBoot的应用程序编译成本地可执行的镜像文件,可以显著提升启动速度、峰值性能以及减少内存使用。

参考资料:面试官:SpringBoot如何优化启动速度

好文阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: