Spring Boot v3.4.1 发布

🐞 Bug 修复 当 Bundle name 为空字符串时,KafkaProperties 无法构建 SSL properties #43563 当属性解析抛出 ConversionFailedException 时,诊断功能很差 #43559 SpringApplicationShutdownHandlers 不按确定顺序运行 #43536 无法找到 @SpringBootConfiguration 导致误导性错误信息 #43507 如果上下文中有多个 ResourceHandlerRegistrationCustomizer Bean,则只使用其中一个 #43497 混合使用专用(dedicated)服务和共享(shared)服务时无法使用 Docker Compose 支持 #43472 Kafka dependency management 不包括 kafka-server 模块 #43454 当 ‘/_ping’ 调用失败并且版本应该修复时,Docker API 版本被错误地报告 #43452 从 KafkaProperties 建立生产者/消费者属性的方法在没有 SSL Bundle 的情况下不便使用 #43448 -Djarmode=tools 中的故障不会持续返回非零退出值 #43436 HttpComponentsClientHttpRequestFactoryBuilder 代替了现有的 defaultRequestConfigCustomizer,而不是对其进行添加 #43429 即使 imagePlatform 为空,spring-boot-maven-plugin 也会设置它 #43424 OnBeanCondition fails to match on annotations when using Scoped Proxies #43423 使用作用域(Scope)代理时,OnBeanCondition 无法与注解匹配 #43382 H2ConsoleAutoConfiguration 会导致提前初始化数据源 Bean #43359 接受大于 2GB 的数字进度 #43356 基于 Servlet 的 UserDetailsServiceAutoConfiguration 在响应式应用程序中处于活动状态 #43334 在 spring.

ClickHouse 数据库简介

1、简介 通过使用联机分析处理(Online Analytical Processing,OLAP),企业可以深入了解当前的运营情况,并确定改进趋势。这通常是通过对汇总的业务数据进行复杂的分析来实现的。 ClickHouse 是一个开源的、列式 OLAP 数据库,因其出色的 性能 而大受欢迎。 本文将带你了解如何在 Spring Boot 中整合、使用 ClickHouse。 2、项目设置 在开始与 ClickHouse 数据库交互之前,我们需要添加一些 SDK 依赖,并正确配置我们的应用。 2.1、依赖 首先,在项目的 pom.xml 中添加必要的依赖: <dependency> <groupId>com.clickhouse</groupId> <artifactId>clickhouse-jdbc</artifactId> <version>0.7.1</version> </dependency> <dependency> <groupId>org.lz4</groupId> <artifactId>lz4-java</artifactId> <version>1.8.0</version> </dependency> clickhouse-jdbc 依赖提供了 JDBC API 的实现,使我们能够与 ClickHouse 数据库建立连接并进行交互。 默认情况下,ClickHouse 使用 LZ4 压缩来存储数据,为此我们添加了 lz4-java 依赖项。 2.2、使用 Flyway 定义数据表 接下来,定义数据库表,并对其执行操作。 使用 Flyway 来管理数据库迁移。这需要添加 flyway-core 和 flyway-database-clickhouse 依赖: <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> </dependency> <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-database-clickhouse</artifactId> <version>10.16.3</version> </dependency> 将这些依赖添加到 pom.xml 之后,在 src/main/resources/db/migration 目录中创建一个名为 V001__create_table.

Spring Filter 中的 chain.doFilter() 方法

1、简介 本文将带你了解 Spring 中 chain.doFilter() 方法的作用。 2、什么是 Spring Filter 在 Spring 应用中,Filter 过滤器以 Java Servlet Filter 为基础,后者代表拦截请求和响应的对象。Filter 是 Java Servlet API 的一部分,在 Web 应用中扮演着重要角色,因为它们位于客户端和服务器处理逻辑之间。 利用它们,我们可以在请求到达 servlet 之前或生成响应之后执行任务。过滤器的常见用例包括 认证和授权 审计和日志 修改请求/响应 过滤器虽然不是 Spring 框架的一部分,但与 Spring 框架完全兼容。我们可以将它们注册为 Spring Bean,并在应用中使用它们。Spring 提供了一些过滤器的实现,其中常见的包括 OncePerRequestFilter 和 CorsFilter。 3、理解 chain.doFilter() 方法 在了解 chain.doFilter() 方法之前,首先要了解过滤器链(Filter Chain)的概念及其在过滤过程中的作用。 过滤器链表示应用于传入请求或传出响应的处理逻辑顺序流。换句话说,它是用于预处理请求或后处理响应的过滤器集合。这些过滤器以明确定义的顺序排列,确保每个过滤器都能在将请求或响应传递到链中的下一阶段之前执行其处理逻辑。 要定义过滤器链,可以使用了 Java Servlet API 中的 FilterChain 接口,其中包含了我们感兴趣的方法。查看该方法的签名,就会发现请求(request)和响应(response)对象被定义为输入参数: void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException; chain.doFilter() 方法将请求和响应传递给链中的下一个过滤器。如果过滤器链中没有过滤器,则会将请求转发给目标资源(通常是 Servlet),并将响应发送给客户端。 3.1、为什么调用 chain.doFilter() 非常重要? 我们可以看到,chain.

在 Spring Data JPA 中创建动态查询

1、概览 在使用 Spring Data 开发应用时,我们经常需要根据选择条件构建动态查询,以便从数据库中获取数据。 本文将带你了解在 Spring Data JPA Repository 中创建动态查询的三种方法:Example 查询、Specification 查询和 Querydsl 查询。 2、示例 创建 School 和 Student 两个实体。这两个实体类之间的关系是一对多,即一个 School 可以有多个 Student: @Entity @Table public class School { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column private Long id; @Column private String name; @Column private String borough; @OneToMany(mappedBy = "school") private List<Student> studentList; // 构造函数、Getter、Setter 省略 } @Entity @Table public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column private Long id; @Column private String name; @Column private Integer age; @ManyToOne private School school; // 构造函数、Getter、Setter 省略 } 除了实体类,还要为 Student 实体定义一个 Spring Data Repository:

正式推出 Spring AI MCP:用于 MCP(模型上下文协议)的 Java SDK

我们很高兴推出 Spring AI MCP,它是模型上下文协议(Model Context Protocol,MCP)的强大 Java SDK 实现。Spring AI 生态系统的这一新成员为 Java 平台带来了标准化的 AI 模型集成能力。 MCP 是什么? 模型上下文协议(MCP)是一种开放式协议,它规范了应用程序为大型语言模型(LLM)提供上下文的方式。MCP 提供了一种将人工智能模型连接到不同数据源和工具的标准化方法,使集成无缝且一致。它可以帮助你在 LLM 的基础上构建代理和复杂的工作流程。LLM 经常需要与数据和工具集成,而 MCP 提供了以下功能: 一个不断扩充的预构建集成列表,你的大语言模型(LLM)可以直接接入使用。 在不同的大语言模型(LLM)提供商和供应商之间灵活切换的能力。 总体结构 MCP 的核心是客户端-服务器(CS)架构,一个应用可以连接多个服务器。 Spring AI MCP 采用模块化架构,包含以下组件: Spring AI 应用: 使用 Spring AI 框架构建希望通过 MCP 访问数据的生成式 AI 应用。 Spring MCP 客户端:与服务器保持 1:1 连接的 MCP 协议的 Spring AI 实现。 MCP 服务器:轻量级程序,每个程序都通过标准化的模型上下文协议公开特定功能。 本地数据源:MCP 服务器可安全访问的计算机文件、数据库和服务。 远程服务:MCP 服务器可通过互联网(如 API)连接的外部系统。 该架构支持广泛的用例,从简单的文件系统访问到复杂的多模型人工智能与数据库和互联网连接的交互。 入门 Spring AI MCP GitHub:https://github.com/spring-projects-experimental/spring-ai-mcp Maven 依赖 在 Maven 项目中添加以下依赖之一

把 Future 转换为 Completablefuture

1、简介 本文将带你了解如何将 Future 转换为 CompletableFuture。通过这种转换,我们可以利用 CompletableFuture 的高级功能,如非阻塞操作、链式任务和更好的错误处理,同时仍可使用返回 Future 的 API 或库。 2、为什么要把 Future 转换为 CompletableFuture? Java 中的 Future 接口表示异步计算的结果。它提供了检查计算是否完成、等待计算完成和检索结果的方法。 不过,Future 也有其局限性,比如阻塞调用需要使用 get() 来获取结果。此外,它还不支持链式调用多个异步任务或处理回调。 而,Java 8 中引入的 CompletableFuture 解决了这些缺陷。它通过用于任务链和回调的 thenApply() 和 thenAccept() 等方法支持非阻塞操作,并使用 exceptionally() 进行错误处理。 通过将 Future 转换为 CompletableFuture,我们可以在使用返回 Future 的 API 或库时利用这些功能。 3、逐步转换 来看看如何将 Future 转换为 CompletableFuture。 3.1、使用 ExecutorService 模拟 Future 要了解 Future 如何工作,我们首先要使用 ExecutorService 模拟异步计算。ExecutorService 是一个用于管理和调度独立线程中任务的框架。这将有助于我们理解 Future 的阻塞特性: @Test void givenFuture_whenGet_thenBlockingCall() throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.

JVM 中的高级选项

1、概览 Java 虚拟机(JVM)是驱动 Java 应用程序的强大引擎。它具有高度可定制性,通过标准选项提供基本配置,通过非标准选项进行一般性性能调优,以及通过高级选项实现精确控制。 高级选项允许开发人员对性能进行微调,诊断问题,并尝试最前沿的功能。 本文将带你了解最著名的高级 JVM 选项以及如何使用它们,从而对 JVM 行为进行更精细的控制。 2、JVM 选项的分类 JVM 参数可分为三大类: 标准选项(-version、-help) 非标准选项(-X: options) 高级选项(-XX: options) 3、理解高级 JVM 选项 高级选项不仅限于基本配置,还可以设置 JVM 的更低级属性。这些选项允许我们调整性能关键参数,如垃圾回收、内存管理和运行时诊断。 其中一些高级选项也是常用的最重要的 JVM 参数。不过,由于它们可以针对特定应用场景进行微调,我们必须谨慎使用。在不清楚应用程序行为的情况下过度定制,可能会导致性能低下、崩溃或意外行为。 此外,高级 JVM 选项并不能保证为所有 JVM 实现所支持,而且可能会发生变化。因此,由于这些选项会随着 JVM 的更新而变化,有些选项可能会过时,或者在较新版本中表现不同。 例如,Java 并发标记和清理垃圾收集(CMS)算法就曾出现过这种情况,该算法在 Java 9 中被弃用,并在 Java 14 中被删除。通过关注官方文档,我们可以在发生任何变化之前及时了解情况。 4、垃圾收集调整 垃圾回收对内存管理至关重要,但也会带来影响性能的停顿。高级选项可控制垃圾回收行为,确保应用程序运行更流畅。 从 Java 9 开始,默认情况下使用垃圾优先的垃圾收集器(G1),旨在平衡吞吐量和延迟。 为了克服 G1 的延迟限制,JDK12 引入了 Shenandoah GC,可以使用 -XX:+UseShenandoahGC 选项启用它。Shenandoah 的可用性取决于 JDK 供应商和版本。 还可以根据专门的工作负载使用其他实现方式。Epsilon 垃圾收集器也非常适合用于性能调优,以检查垃圾收集是否会影响我们程序的性能。 5、内存管理 如上所述,垃圾回收是内存管理的重要组成部分,但它只是 JVM 中更大的内存管理生态系统的一部分。 要实现最佳性能,同样重要的是配置内存分配、管理堆大小以及了解堆外内存的工作原理,特别是对于内存密集型应用或有特定性能要求的系统。 回顾一下与内存管理相关的一些高级 JVM 选项:

使用 Java 在 PostgreSQL 中存储日期和时间

1、简介 在数据库中存储日期(Date)和时间(Time)信息是软件开发中的一项常见任务。由于有许多不同的格式、时区和存储格式,处理日期和时间可能是一项复杂的任务,如果处理不慎,可能会导致许多问题。 本文将带你了解 Java Date / Time API 提供的日期和时间类,以及 PostgreSQL 如何持久化这些类。 2、设置 本文使用 Spring Boot 和 Spring Data JPA 在 PostgreSQL 数据库中持久化日期和时间值。 首先,创建一个实体,其中包含 Java Date / Time API 中不同日期和时间类的字段: @Entity public class DateTimeValues { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private Date date; private LocalDate localDate; private LocalDateTime localDateTime; private Instant instant; private ZonedDateTime zonedDateTime; private LocalTime localTime; private OffsetDateTime offsetDateTime; private java.sql.Date sqlDate; // Getter / Setter 省略 } 此外,还要添加一个默认构造函数,以固定时间初始化所有日期/时间字段:

JsonMappingException:Can not deserialize instance of java.util.HashMap out of START_ARRAY token

1、概览 本文将带你了解如何解决 Jackson 异常:JsonMappingException: Can not deserialize instance of java.util.HashMap out of START_ARRAY token。 2、理解异常 简而言之,Jackson 在反序列化 JSON 字符串时抛出 JsonMappingException 来指示映射错误。而,“Can not deserialize instance of java.util.HashMap out of START_ARRAY token” 异常消息表示预期的数据结构与实际的 JSON 字符串不匹配。 这里出现不匹配是因为 Jackson 期望的是 List 而不是 HashMap。反序列化过程不知道如何将指定的 JSON 数组转换为 HashMap。因此出现异常。 3、示例 来看一个会导致 Jackson 出现 JsonMappingException 异常的例子。 为了简单起见,假设我们有一个 JSON 数组,其中每个元素都代表一个由名(firstName)和姓(lastName)定义的人: [ { "firstName":"Abderrahim", "lastName":"Azhrioun" }, { "firstName":"Nicole", "lastName":"Smith" } ] 现在,如果尝试将 JSON 数组直接反序列化为 Map,将导致 JsonMappingException: @Test public void givenJsonArray_whenDeserializingToMap_thenThrowException() { final String json = "[{\"firstName\":\"Abderrahim\",\"lastName\":\"Azhrioun\"}, {\"firstName\":\"Nicole\",\"lastName\":\"Smith\"}]"; final ObjectMapper mapper = new ObjectMapper(); Exception exception = assertThrows(JsonMappingException.

Reactor 2024.0 发布,支持 HTTP/3

HTTP/3 是 Hypertext Transfer Protocol(超文本传输协议,即 HTTP)的最新主要版本,其规范已于 2022 年 6 月定稿。该版本旨在提高性能、可靠性和安全性。与之前的版本不同,HTTP/3 使用 QUIC 而不是 TCP 作为传输层。QUIC 是一种基于 UDP 的多路复用安全传输协议,内置 TLS 1.3 加密,默认情况下 QUIC 是加密的。 要进一步了解 HTTP/3 的性能和优势,可以查看 《什么是 HTTP/3》。 有关浏览器采用情况的信息,请参阅《检查 HTTP/3 使用情况》,其中还提供了不同浏览器使用的 HTTP 版本的原始数据。 Reactor Netty 1.2(Reactor 2024.0 发布系列的一部分)添加了对 HTTP/3 的实验性支持。通过这个新版本的 Reactor Netty,你可以配置你的 Spring Boot 应用和 Spring Cloud Gateway 来支持 HTTP/3。 下面让我们看看如何配置 HTTP/3 支持。 配置 Reactor BOM Version Spring Boot 3.4 默认集成了 Reactor 2024.0 发布系列! 如果你运行的是旧版本的 Spring Boot,你可以将 Reactor BOM 升级到 2024.