Spring Boot 2.2 中的延迟初始化

技术 | Andy Wilkinson | 2019 年 3 月 14 日 | ...

Spring Boot 2.2 的最近宣布的第一个里程碑版本引入了对延迟初始化的支持。本文介绍了这项新功能,并解释了如何以及何时启用它。

延迟初始化意味着什么?

Spring Framework 早在 11 年前源代码迁移到 Git 之前就已支持 Bean 的延迟初始化。默认情况下,当应用上下文刷新时,上下文中的每个 Bean 都会被创建并注入其依赖项。相比之下,当 Bean 定义配置为延迟初始化时,只有在需要时才会创建它并注入其依赖项。

启用延迟初始化

在任何 Spring Boot 版本中,如果你愿意自己动手编写 BeanFactoryPostProcessor,都可以启用延迟初始化。Spring Boot 2.2 通过引入一个新的属性 spring.main.lazy-initialization 使其更加容易(在 SpringApplicationSpringApplicationBuilder 上也有等效方法)。当设置为 true 时,应用程序中的 Bean 定义将被配置为使用延迟初始化。

延迟初始化的优势

延迟初始化可以显著减少启动时间,因为在应用程序启动期间加载的类更少,创建的 Bean 也更少。例如,一个使用 Actuator 和 Spring Security 的小型 Web 应用程序通常需要 2500 毫秒启动,启用延迟初始化后只需 2000 毫秒。具体改进效果因应用程序而异,取决于其 Bean 的依赖关系图结构。

DevTools 怎么样?

Spring Boot 的 DevTools 已经显著提升了开发人员的生产力。无需每次尝试更改时都重新启动 JVM 和应用程序,DevTools 可以在同一 JVM 中实现应用程序的热重启。热重启的一个显著优势是它让 JIT 有更多机会优化涉及应用程序启动的代码。几次重启后,最初的 2500 毫秒启动时间减少了近 80%,接近 500 毫秒。有了延迟初始化,我们可以做得更好。将 spring.main.lazy-initialization 设置为 true 可以让我们的应用程序在 IDE 中直接在 400 毫秒内重启。

延迟初始化的缺点

正如我们上面所见,启用延迟初始化可以显著缩短启动时间。你可能想一直启用它,或者好奇为什么我们没有默认启用它。延迟初始化有一些缺点,这些缺点让我们认为在你决定这样做有意义后选择启用是更好的方式。

由于类不再加载,Bean 也只有在需要时才创建,延迟初始化可能会掩盖之前在启动时就会发现的问题。这些问题可能包括找不到类定义错误(no class def found)、内存不足错误(out of memory)以及配置错误导致的失败。

在 Web 应用程序中,延迟初始化可能会导致触发 Bean 初始化的 HTTP 请求增加延迟。这通常只发生在第一个请求上,但可能会对负载均衡和自动伸缩产生不利影响。

这个功能开启了吗?

如果你不确定延迟初始化对你的应用程序有什么影响,或者你想验证另一个框架的行为是否符合你的需求并与他们的宣称相符,使用调试器会很有帮助。通过在你的某个 Bean 的构造函数中设置断点,你可以看到它何时被初始化。例如,在启用延迟初始化的 Spring Boot Web 应用程序中,你会发现 @Controller Bean 直到第一个请求到达 Spring MVC 的 DispatcherServlet 或 Spring WebFlux 的 DispatcherHandler 时才被创建。

何时启用延迟初始化

正如我们上面所见,延迟初始化可以显著改进启动时间,但也有一些明显的缺点,因此谨慎启用它非常重要。

延迟初始化几乎没有缺点且益处很大的一方面是开发阶段。在应用程序迭代过程中,延迟初始化和 DevTools 热重启带来的更短启动时间可以极大地提高你的生产力。

另一个可以从延迟初始化中获益的领域是应用程序的集成测试。你可能已经在使用 Spring Boot 的测试切片(test slices)来限制特定类型测试中初始化的 Bean 数量,从而减少测试执行时间。延迟初始化提供了另一种机制来达到类似的效果。如果你无法组织应用程序以便于进行测试切片,或者对于特定类型的测试没有可用的切片,启用延迟初始化将限制初始化的 Bean 仅限于测试所需的 Bean。这将减少测试执行时间,尤其是在开发期间单独运行测试时。

最后,你可能希望考虑在生产环境中启用延迟初始化。如果这样做,应谨慎行事。对于 Web 应用程序,容器编排可能会受益于能够更快响应的 /health 端点,但你也需要注意,当第一个请求发送到应用程序自己的端点时,可能会增加延迟。你还应注意在禁用延迟初始化的情况下为应用程序的 JVM 分配内存,以避免所有组件使用后出现意外的内存不足错误。

订阅 Spring 快讯

订阅 Spring 快讯,保持联系

订阅

保持领先

VMware 提供培训和认证,助你加速进步。

了解更多

获取支持

Tanzu Spring 通过一个简单的订阅提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看全部