加快Spring Boot启动时间

问题描述 投票:70回答:8

我有一个Spring Boot应用程序。我添加了很多依赖项(不幸的是,看起来我需要所有这些依赖项)并且启动时间上升了很多。只是做一个SpringApplication.run(source, args)需要10秒。

虽然这与“使用”相比可能没那么多,但我很不高兴它需要那么多,主要是因为它打破了开发流程。此时应用程序本身相当小,所以我假设大部分时间都与添加的依赖项有关,而不是与应用程序类本身有关。

我假设问题是类路径扫描,但我不知道如何:

  • 确认是问题(即如何“调试”Spring Boot)
  • 如果它真的是原因,我怎么能限制它,所以它变得更快?例如,如果我知道某些依赖项或包不包含Spring应扫描的任何内容,是否有办法限制它?

我认为enhancing Spring to have parallel bean initialization during startup会加快速度,但是这个增强请求自2011年开始,没有任何进展。我在Spring Boot本身看到了一些其他的努力,例如Investigate Tomcat JarScanning speed improvements,但这是特定于Tomcat的并且已经被放弃了。

本文:

虽然针对集成测试,建议使用lazy-init=true,但我不知道如何使用Java配置将此应用于Spring Boot中的所有bean - 这里有任何指针吗?

任何(其他)建议都会受到欢迎。

java performance spring-boot startup
8个回答
45
投票

Spring Boot进行了许多可能不需要的自动配置。因此,您可能只想缩小应用程序所需的自动配置范围。要查看包含的自动配置的完整列表,只需在DEBUG模式下运行org.springframework.boot.autoconfigure的日志记录(logging.level.org.springframework.boot.autoconfigure=DEBUG中的application.properties)。另一种选择是使用--debug选项运行spring boot应用程序:java -jar myproject-0.0.1-SNAPSHOT.jar --debug

在输出中会有这样的东西:

=========================
AUTO-CONFIGURATION REPORT
=========================

检查此列表并仅包含您需要的自动配置:

@Configuration
@Import({
        DispatcherServletAutoConfiguration.class,
        EmbeddedServletContainerAutoConfiguration.class,
        ErrorMvcAutoConfiguration.class,
        HttpEncodingAutoConfiguration.class,
        HttpMessageConvertersAutoConfiguration.class,
        JacksonAutoConfiguration.class,
        ServerPropertiesAutoConfiguration.class,
        PropertyPlaceholderAutoConfiguration.class,
        ThymeleafAutoConfiguration.class,
        WebMvcAutoConfiguration.class,
        WebSocketAutoConfiguration.class,
})
public class SampleWebUiApplication {

代码是从this blog post复制的。


23
投票

到目前为止,投票最多的答案并没有错,但它没有深入到我喜欢的深度,也没有提供任何科学证据。 Spring Boot团队进行了一项练习,以减少Boot 2.0的启动时间,并且11226票证包含许多有用的信息。还有一张票据7939可以在条件评估中添加时间信息,但它似乎没有特定的ETA。

调试启动启动的最有用,最有条理的方法是由Dave Syer完成的。 https://github.com/dsyer/spring-boot-startup-bench

我也有一个类似的用例,所以我采用了Dave与JMH进行微基准测试的方法并运行它。结果是boot-benchmark项目。我设计它可以用来衡量任何Spring Boot应用程序的启动时间,使用bootJar(之前在Boot 1.5中称为bootRepackage)Gradle任务生成的可执行jar。随意使用它并提供反馈。

我的调查结果如下:

  1. CPU很重要。很多。
  2. 使用-Xverify:none启动JVM有很大帮助。
  3. 排除不必要的自动配置有帮助。
  4. 戴夫推荐JVM参数-XX:TieredStopAtLevel=1,但我的测试没有显示出明显的改进。此外,-XX:TieredStopAtLevel=1可能会减慢您的第一个请求。
  5. 主机名解析的reports很慢,但我没有发现它对我测试的应用程序有问题。

6
投票

正如在这个问题/答案中所描述的,我认为最好的方法是不要只添加您认为需要的那些,而是排除您不需要的依赖项。

见:Minimise Spring Boot Startup Time

综上所述:

您可以看到正在进行的操作,并启用调试日志记录,就像从命令行启动应用程序时指定--debug一样简单。您还可以在application.properties中指定debug = true。

此外,您可以在application.properties中设置日志记录级别,如下所示:

logging.level.org.springframework.web:DEBUG logging.level.org.hibernate:ERROR

如果检测到您不想要的自动配置模块,则可以禁用它。这方面的文档可以在这里找到:http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-disabling-specific-auto-configuration

一个例子如下:

@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}

4
投票

Spring Boot 2.2.M1增加了在Spring Boot中支持Lazy Initialization的功能。

默认情况下,在刷新应用程序上下文时,将创建上下文中的每个bean并注入其依赖项。相比之下,当bean定义被配置为懒惰地初始化时,它将不会被创建,并且在需要之前不会注入其依赖项。

启用延迟初始化将spring.main.lazy-initialization设置为true

有关详细信息,请查看Doc


-1
投票

如果您正在尝试优化手动测试的开发周转,我强烈建议使用devtools

使用spring-boot-devtools的应用程序将在类路径上的文件发生更改时自动重新启动。

只需重新编译 - 服务器将自动重启(对于Groovy,您只需要更新源文件)。如果您正在使用IDE(例如'vscode'),它可能会自动编译您的java文件,因此只需保存一个java文件就可以间接启动服务器重启 - 而Java在这方面就像Groovy一样无缝。

这种方法的优点在于增量重启会使一些从头开始的启动步骤短路 - 这样您的服务就可以更快地备份和运行!


不幸的是,这对部署或自动化单元测试的启动时间没有帮助。


-2
投票

警告:如果您不使用Hibernate DDL生成自动数据库模式,并且您不使用L2缓存,则此答案不适用于您。向前滚动。

我的发现是Hibernate为应用程序启动增加了大量时间。禁用L2缓存和database initialization可以加快Spring Boot应用程序的启动速度。保留缓存为生产并为您的开发环境禁用它。

application.yml:

spring:
  jpa:
    generate-ddl: false
    hibernate:
      ddl-auto: none
    properties:
      hibernate:
        cache:
          use_second_level_cache: false
          use_query_cache: false

检测结果:

  1. L2缓存是ON和ddl-auto: update INFO 5024 --- [restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 23331 ms INFO 5024 --- [restartedMain] b.n.spring.Application : Started Application in 54.251 seconds (JVM running for 63.766)
  2. L2缓存是OFF和ddl-auto: none INFO 10288 --- [restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 9863 ms INFO 10288 --- [restartedMain] b.n.spring.Application : Started Application in 32.058 seconds (JVM running for 37.625)

现在我想知道我将如何处理所有这些空闲时间


-3
投票

我觉得很奇怪之前没有人建议这些优化。以下是开发时优化项目构建和启动的一些常规技巧:

  • 从防病毒扫描程序中排除开发目录: 项目目录 构建输出目录(如果它在项目目录之外) IDE索引目录(例如〜/ .IntelliJIdea2018.3) 部署目录(Tomcat中的webapps)
  • 升级硬件。使用更快的CPU和RAM,更好的互联网连接(用于下载依赖项)和数据库连接,切换到SSD。视频卡没关系。

警告

  1. 第一种选择是降低安全性的代价。
  2. 第二种选择需要花钱(显然)。

-6
投票

对我而言,听起来你使用了错误的配置设置。首先检查myContainer和可能的冲突。要确定谁在使用最多的资源,每次检查每个依赖项的内存映射(请参阅数据量!) - 这需要大量时间,以及......(以及SUDO权限)。顺便说一句:您是否经常针对依赖项测试代码?


推荐问答