Bootiful Spring Boot 3.4:Spring Boot

工程 | Josh Long | 2024 年 11 月 24 日 | ...

现在我们又回到了起点:Spring Boot 3.4!这个版本将所有内容整合在一起。当你审视 Spring Boot 时,请记住它标准化了所有项目的集成,并尽可能地尝试平滑使用这些项目时可能出现的集成问题。此外,它还提供了对所有其他框架用户都有益的设施。

举例来说:当我们为 Spring Framework 6 和 Spring Boot 3 引入 GraalVM 原生镜像支持时,我们分了三个阶段完成。第一:在 Spring Framework 中交付了一个组件模型、生命周期和核心 SPI。第二:这个核心组件模型使得所有基于 Spring Framework 构建的其他项目(您知道的:Spring Data、Spring Security、Spring Batch、Spring Integration 等)能够为自己的项目提供恰当的 GraalVM 原生镜像体验。最后,第三:Spring Boot 将这种体验打包成了一个整体,为自身以及一些第三方项目提供了 GraalVM 集成,提供了构建工具插件,并总体上安排好了一切,以便在代码运行之前,那些必须在编译时发生的事情能够完成。Spring Boot 还集成了诸如 GraalVM 可达性元数据仓库和用于容器化 GraalVM 原生镜像的 Buildpacks 支持等环境因素。当一切都做得恰当,其结果令人惊叹,Spring Boot 席卷全球是有原因的。它让您专注于生产,并让 Spring 保持其原有的特色。(团队合作成就梦想!)

本次发布也不例外。这个版本包含了很多精彩的内容!让我们来按惯例 回顾一下发布说明中的新内容和创新之处,然后深入探讨一些我最喜欢的新功能(忽略 Spring Boot 3.4 发布中包含的所有令人惊叹的项目功能!)。

  • 他们增强并规范了底层 HttpRequestFactory 实现的自动配置体验,这些实现可以插入到 RestClientRestTemplate 中。如果您有 Apache HTTP Components,您将获得一个 HttpComponentsClientHttpRequestFactory。如果没有,但您有 Jetty,您将获得一个 JettyClientHttpRequestFactory。如果没有,但您有 Reactor Netty,您将获得一个 ReactorClientHttpRequestFactory。如果没有,但您有较新版本的 JDK,您将获得 JdkClientHttpRequestFactory。如果没有,并且您没有任何其他东西,您将获得一个 SimpleClientHttpRequestFactory,本质上就是 JDK 的 HttpURLConnection。真是糟糕!注意:此版本还改变了默认设置。之前,即使在支持 HttpClient 的 JVM 上,默认也会获得 HttpURLConnection
  • 还有一个新的 ClientHttpRequestFactoryBuilder,它允许您以编程方式一致地构建这些实现。
  • 所有这些客户端默认都遵循重定向,但现在您可以选择退出。
  • 应用程序现在默认优雅地关闭。Spring Boot 已经有了优雅关闭功能多年。基本思想是,当容器编排器、平台或操作员向 JVM 发送关闭(SIGTERM)命令时,Spring Boot 会立即关闭。它会允许任何正在进行的事务在可配置的时间内逐渐完成。然后,它将关闭。在此期间,它将拒绝新的 HTTP 请求等。
  • 您现在可以使用 @AutoConfigureTestDatabase 和容器,而无需告知测试支持您不希望替换它。
  • 此版本为 Actuator 端点可见性带来了更粗粒度的支持。
  • 此版本的基线是 HTMLUnit 4.3,它位于不同的 Maven 坐标下。因此,请相应地更新您的代码。
  • 引入了对结构化日志记录的支持,内置了对 Elastic Common Schema (ecs)、Graylog Extended Log Format (gelf) 和 Logstash (logstash) 的支持。要启用结构化文件日志记录,请将 logging.structured.format.file 设置为 ecsgelflogstash。同样,将 logging.structured.format.console 设置为启用结构化控制台日志记录。
  • 现在可以通过 gRPC 传输发送 OTLP spans。
  • 现在可以使用客户端证书向 Couchbase 集群进行身份验证,作为基本用户名和密码身份验证的替代方案。
  • 自动配置的 FreeMarker `Configuration` 对象使用的 FreeMarker 变量现在可以自定义。
  • 现在 ActiveMQ Classic 再次支持嵌入式代理,自动配置已更新以支持它。(如果您添加 org.apache.activemq:activemq-broker,嵌入式 ActiveMQ 就回来了!)
  • 现在有一个机制来记录和标记自动配置的弃用:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.replacements
  • 使用虚拟线程时,OtlpMeterRegistry 和 Undertow 都能正确处理。
  • Spring Boot 现在默认使用 paketobuildpacks/builder-jammy-java-tiny。此构建器开箱即用地支持 ARM 和 x64 平台。
  • Docker Compose 现在支持多个 Docker Compose 配置文件,并在启动时运行 Docker Compose 文件时支持传递给 Docker Compose 命令行自定义参数。
  • Spring Boot Actuator 端点反映了更多关于 SSL 捆绑包的信息。
  • /actuator/scheduledtasks 端点处可以获得有关计划任务的附加信息。

这么多新功能!从何说起呢?我不太确定,所以我决定不看代码,而是关注 Spring Boot 控制的运行时体验,特别是两个功能:Apple Silicon 上的 Buildpacks 中的 GraalVM 原生镜像和优雅关闭。让我们看看优雅关闭。这方面没什么需要理解的。

让我们来看看一个特别不起眼的小类,它在很多方面都做得很好。

package com.example.bootiful_34.boot;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestClient;

@Controller
@ResponseBody
class GracefulController {

	private final RestClient http;

	GracefulController(RestClient.Builder http) {
		this.http = http.build();
	}

	@GetMapping("/delay")
	String delay() {
		return this.http.get().uri("https://httpbin.org/delay/5").retrieve().body(String.class);
	}

}

首先,这个类使用了更新的自动配置的 RestClient 构建器,这是 Spring Boot 3.4 中的新功能。我运行在 Java 21+(实际上是 Java 23)上,所以我得到了新的 JdkClientHttpRequestFactory,它基于出色的 java.net.http.HttpClient。这已经是一个巨大的进步了,而我们才刚刚开始!

发送到此控制器端点的每个请求都会导致向 HTTPBin 端点发出一个 HTTP 请求。HTTPBin 网站旨在人为地延长响应的持续时间,持续我们在此 HTTP 请求中指定的秒数。在这种情况下,是 5 秒。这很长时间!而且请记住,我们使用的是 servlet 容器,默认情况下每个请求都需要一个线程。所以您调用 localhost:8080/delay(记住,由于我们之前用 Spring Security 锁定了应用程序,您可能需要登录...),它会阻塞五秒钟。它会一直待在那里,在宝贵的线程上浪费时间,而默认情况下线程数量非常少。幸运的是,这是 Spring Boot,所以只需翻转一个配置开关,我们就启用了 Java 21 的虚拟线程:spring.threads.virtual.enabled=true

现在,当用户发出请求时,RestClient 发起一个请求,当它在那里等待五秒钟时,JVM 会自动将请求从操作系统线程移到一个类似暂停的状态。为什么这很重要?因为现在有人可以利用这个线程来做别的事情!这带来了更好、更少负罪感的扩展性。但这并不是一个新功能。您从 Spring Boot 3.2 开始就可以使用它。

在这种情况下,每个请求也需要时间来完成。五秒加上网络延迟,肯定是的。那么,如果操作员(Kubernetes 或 Cloud Foundry)过来想要关闭应用程序会怎样?我们仍在等待请求完成!JVM 也是如此。默认情况下是 30 秒,您可以用 spring.lifecycle.timeout-per-shutdown-phase=30s 进行配置。因此,如果平台关闭了应用程序(您可以通过在 JetBrains IntelliJ IDEA 中按下红色方块来模拟它),它会等待最多 30 秒来完成任何正在进行的请求。然后它会关闭。否则,它会立即关闭。真好。

对于 Apple Silicon 用户来说,一个不错的改进是 Buildpacks 支持已更新,可以在 Apple Silicon 上正常工作。

那么,让我们将此应用程序本身转换为 GraalVM 原生镜像。在 bootiful-34 文件夹的根目录下运行以下命令。

./mvnw -DskipTests clean -Pnative spring-boot:build-image

这是我用来在我的 Apple Silicon 驱动的 Apple M4 笔记本电脑上编译并运行它的脚本。

#!/usr/bin/env bash

rm -rf target
./mvnw -DskipTests spring-javaformat:apply 
./mvnw -DskipTests -Pnative spring-boot:build-image 

这是我用来运行它的脚本。这假设您已经在本地运行了 Docker 或类似 Docker 的东西,并且您的主机操作系统中有一个名为 SPRING_AI_OPENAI_API_KEY 的环境变量,如同我一样。

#!/usr/bin/env bash

export SPRING_DATASOURCE_URL=jdbc:postgresql://host.docker.internal/mydatabase
docker run \
  -e SPRING_DATASOURCE_URL=$SPRING_DATASOURCE_URL \
  -e SPRING_AI_OPENAI_API_KEY=$SPRING_AI_OPENAI_API_KEY \
  docker.io/library/bootiful-34:0.0.1-SNAPSHOT

你知道什么让我震惊吗?有时,至少在我的机器上,在 Apple Silicon 上运行 GraalVM 原生镜像二进制文件的 Linux 容器比直接编译到 macOS 原生二进制文件并在 macOS 上运行时运行得更快!我一点也不知道为什么!这个应用程序简直是集大成者!我们有一个 Web 服务器,一个 Spring Batch Job,几个 Spring Integration 流,大量的 SQL DataSource 访问,Spring Modulith,本地调用函数的 Spring AI,三种不同的安全机制以及一个完整的 OAuth IDP(Spring Authorization Server),一些 HTTP 端点,一些 Spring Data JDBC 实体和存储库,等等。所以,请相信我,这不是一个典型的用例,我并没有期望二进制文件在我的 Linux 机器上运行得更快。在 macOS 上直接运行时,有时启动需要 0.450 到 0.5 秒。在 Docker 中,我见过它运行速度高达 0.264 秒。我感到很困惑!

在我更典型的专注于应用程序的服务中,数字更加悬殊。我在同一个 Github 仓库中有一个更简单的应用程序,名为 demodemo 只是 Spring Data JDBC 与 PostgreSQL 和 Spring MVC 进行通信。它什么都不做。Buildpacks 版本的原生镜像启动速度稳定在 0.050 秒左右,而 macOS 原生镜像的启动速度约为 0.080 秒!虽然不是两倍,但也不是什么都没有!我喜欢 Buildpacks!而且现在可以在我的本地机器上测试一切正常,真是太好了。

Spring Boot 提供了一个坚实的基础,我们可以在此基础上构建其他项目。已有两个项目发布了 Spring Boot 3.4 支持:Spring Modulith 和 Spring AI。所以,我在这里将介绍这两个项目。另一个基于 Spring Boot 3.4 的项目——Spring Cloud——也将很快到来。

Spring Boot 3.4 太棒了。请记住,这个版本是我们在明年迎来 Spring Boot 4.0 之前的最后一个版本之一,所以当您升级时,请注意任何弃用项。现在就解决这些弃用项是最好的!

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

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

了解更多

获得支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一份简单的订阅。

了解更多

即将举行的活动

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

查看所有