Spring

在 Spring 应用中实现 Kafka Consumer 重试消费

1、概览 本文将会带你学习在 Spring 应用中实现 Kafka Consumer 重试消费的 2 种方式,及其优缺点。 关于如何在 Spring 中整合 Kafka 的细节,请参阅 这里。 2、项目设置 创建一个新的 Spring Boot 项目,并添加 spring-kafka 依赖: <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>3.0.1</version> </dependency> 创建一个对象: public class Greeting { private String msg; private String name; // 构造函数、get、set 方法省略 } 3、Kafka Consumer Kafka Consumer(消费者)是从 Kafka 集群中读取数据的客户端应用程序。它订阅一个或多个 topic,并消费已发布的消息。Producer (生产者)向 topic 发送消息,topic 是存储和发布记录的类别名称。topic 被分为多个分区,以便横向扩展。每个分区都是一个不可更改的消息序列。 Consumer 可以通过指定偏移量(即消息在分区中的位置)来读取特定分区中的消息。Ack(确认)是消费者发送给 Kafka broker 的消息,表示它已成功处理了一条记录。一旦 ACK 被发送,消费者偏移量(consumer offset)将会被更新。 这将确保消息已被消费,并且不会再次传递给当前 Listener。 3.1、Ack 模式 Ack 模式决定了 broker 何时更新消费者偏移量(consumer offset)。

将 byte[] 转换为 MultipartFile

1、概览 MutlipartFile 是 Spring 提供的一个接口,用于接收 multipart 请求中的文件参数。Spring 没有为其提供任何默认实现,但提供了一个用于测试的实现。 在本教程中,我们将学习如何将字节数组转换为 MultipartFile。 2、实现 MultipartFile 接口 让我们创建自己的 MultipartFile 接口实现,并封装传入的字节数组: public class CustomMultipartFile implements MultipartFile { private byte[] input; @Override public String getName() { return null; } @Override public String getOriginalFilename() { return null; } @Override public String getContentType() { return null; } // 下一个代码段中定义了接口的其他方法 } 我们在类中定义了一个 byte[] 属性,存储传入的字节数组。接口中定义的其他几个描述性方法,可以根据需求来实现。这里默认返回 null。 剩余的几个接口方法是必须要实现的,如下: public class CustomMultipartFile implements MultipartFile { // 前一段儿代码省略... @Override public boolean isEmpty() { return input == null || input.

Spring 6 中的 AOT(Ahead of Time)优化

1、概览 Spring 6 提供了一项新功能,有望优化应用程序的性能: Ahead-of-Time(AOT) 编译支持。 在本文中,我们将了解 Spring 6 中 AOT 优化功能的工作原理、优点以及使用方法。 2、AOT 编译 2.1、JIT 编译器 对于最常用的 Java 虚拟机(JVM),如 Oracle 的 HotSpot JVM 和 OpenJDK,当我们编译源代码(.java 文件)时,生成的字节码存储在 .class 文件中。这样,JVM 就会使用 JIT(Just-In-Time,即时编译) 编译器将字节码转换为机器码。 此外,JIT 编译涉及 JVM 对字节码的解释,以及在运行时将频繁执行的代码动态编译为本地机器码。 2.2、AOT 编译器 Ahead-of-Time(AOT,提前编译或预编译)是一种在应用程序运行前将字节码预编译为本地机器码的技术。 Java 虚拟机(JVM)通常不支持这一功能。不过,甲骨文已在 OpenJDK 项目中发布了一项针对 HotSpot JVM 的实验性 AOT 功能,名为 “GraalVM Native Image”,允许进行 AOT 编译。 预编译代码后,计算机处理器可直接执行代码,无需 JVM 解释字节码,从而缩短了启动时间。 关于 AOT 编译器的更多细节可以参考 官方文档。 3、Spring 6 中的 AOT 支持 3.1、AOT 编译优化 在构建 Spring 6 应用程序时,我们需要考虑三种不同的运行时选项:

Spring 6 中的声明式 HTTP 接口

1、概览 在 Spring 6 和 Spring Boot 3 中,我们可以使用 Java 接口来定义声明式的远程 HTTP 服务。这种方法受到 Feign 等流行 HTTP 客户端库的启发,与在 Spring Data 中定义 Repository 的方法类似。 在本教程中,我们将首先了解如何定义 HTTP 接口,以及可用的 exchange 方法注解和支持的方法参数和返回值。接着,学习如何创建一个实际的 HTTP 接口实例,即执行所声明 HTTP exchange 的代理客户端。 最后,我们将介绍如何对声明式 HTTP 接口及其代理客户端进行异常处理和测试。 2、HTTP 接口 声明式 HTTP 接口包括用于 HTTP exchange 的注解方法。我们可以通过使用带注解的 Java 接口来简单地表达远程 API 的细节,然后让 Spring 生成实现该接口并执行 exchange 的代理。这有助于减少样板代码的编写。 2.1、Exchange 方法 @HttpExchange 是我们可以应用于 HTTP 接口及其 exchange 方法的根注解。如果我们将其应用于接口层,那么它就会应用于所有 exchange 方法。这对于指定所有接口方法的共同属性(如 content type 或 URL 前缀)非常有用。 所有 HTTP 方法都有对应的注解: @GetExchange 用于 HTTP GET 请求。 @PostExchange 用于 HTTP POST 请求。 @PutExchange 用于 HTTP PUT 请求。 @PatchExchange 用于 HTTP PATCH 请求。 @DelectExchange 用于 HTTP DELETE 请求。 让我们使用不同的 HTTP 方法注解,来为远程 API 定义一个声明式的 HTTP 接口:

在 Spring 应用中获取当前的 Applicationcontext

1、概览 在这本教程中,我们将了解如何在 Spring 应用中获取当前的 ApplicationContext。 2、ApplicationContext ApplicationContext 代表 Spring IoC 容器,其中包含应用程序创建的所有 Bean。它负责实例化、配置和创建 Bean。此外,它还从 XML 或 Java 中提供的配置元数据中获取 Bean 的信息。 ApplicationContext 是 BeanFactory 的子接口。除了 BeanFactory 的功能外,它还包括消息解析和国际化、资源加载和事件发布等功能。此外,它还具有加载多个 context 的功能。 每个 Bean 都是在容器启动后实例化的。 我们可能希望使用此容器访问应用中的其他 Bean 和资源。我们将学习两种在 Spring 应用中获取当前 ApplicationContext 的方法。 3、ApplicationContext Bean 获取当前 ApplicationContext 的最简单方法是使用 @Autowired 注解将其注入到我们的 Bean 中。 首先,声明实例变量,并使用 @Autowired 对其进行注解: @Component public class MyBean { @Autowired private ApplicationContext applicationContext; public ApplicationContext getApplicationContext() { return applicationContext; } } 也可以使用 @Inject 来代替 @Autowired。

Spring Boot 中的新 JDBC 客户端: JdbcClient

Spring 6.1 引入了新的 JdbcClient API,它是 JdbcTemplate 的封装,可使用 fluent 风格的 API 执行数据库操作。 本文将会带你学习如何使用 JdbcClient 以简化的方式实现各种数据库操作。 首先,访问 https://start.springboot.io,选择 Spring JDBC、PostgreSQL Driver、Flyway Migration 和 Testcontainers starter,创建一个 Spring Boot 应用程序。 注:在撰写本文时,Spring Boot 3.2.0-M2 已发布,因此我们将选择 3.2.0 (M2) 作为 Spring Boot 版本。 创建 Bookmark 类 先创建一个表示书签的 Java record,如下所示: import java.time.Instant; public record Bookmark(Long id, String title, String url, Instant createdAt) {} 创建 Flyway 迁移脚本 在 src/main/resources/db/migration 目录下添加以下迁移脚本。 V1__create_tables.sql: create table bookmarks ( id bigserial primary key, title varchar not null, url varchar not null, created_at timestamp ); 使用 JdbClient 执行 CRUD 操作 使用 JdbcClient API 在 Bookmark 类上实现 CRUD 操作。

RestTemplate 中 exchange()、postForEntity() 和 execute() 之间的区别

1、简介 在本教程中,我们将了解 RestTemplate 类中 exchange()、postForEntity() 和 execute() 方法之间的区别。 2、RestTemplate 是啥? RestTemplate 是 Spring 框架 中的一个工具类,它能让发送 HTTP 消息和处理响应变得简单。RestTemplate 类提供了许多功能,非常适合编写简单的 HTTP 客户端: 支持所有标准 HTTP 方法(GET、POST 等)。 能够处理所有标准 MIME Type(JSON、XML、表单等)。 高级 API 允许我们使用 Java 代码进行配置,并避免复杂的序列化问题。 可使用 ClientHttpRequestInitializer 和 ClientHttpRequestInterceptor 接口进行自定义。 2.1、废弃警告 从 Spring 5 开始,RestTemplate 类逐渐被弃用。虽然它在 Spring 6 中仍然存在,但维护者已经明确表示,该类今后不会再有任何改进,只接受较小的错误和安全修复。 因此,我们鼓励开发人员使用 WebClient。该类拥有更现代的 API,支持同步、异步和 stream 场景。 3、RestTemplate 基本用法 RestTemplate 通过提供具有相应名称的 public 方法,让使用标准 HTTP 方法变得简单。 例如,要发送 GET 请求,我们可以使用带有 getFor 前缀的多种重载方法之一。其他 HTTP 方法也类似,包括 POST、PUT、DELETE、HEAD 和 PATCH。 所有这些方法的结构几乎相同。它们基本上只需要有关的 URL 信息,以及请求和响应体的表示方法。header 等信息会自动生成。

在 Spring 应用中整合 Apache Kafka 以生产、消费消息

1、概览 Apache Kafka 是一个分布式且容错的流处理系统。 在本教程中,我们将介绍 Spring 对 Kafka 的支持以及它在原生 Kafka Java 客户端 API 之上提供的抽象层。 Spring Kafka 通过 KafkaTemplate 和使用 @KafkaListener 注解的消息驱动的POJO,提供了简单且典型的 Spring template 编程模型。 2、安装和设置 要下载和安装 Kafka,请参阅 此处 的官方指南。 我们需要在 pom.xml 中添加 spring-kafka 依赖: <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>3.0.0</version> </dependency> 然后按如下方法配置 spring-boot-maven-plugin: <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.baeldung.spring.kafka.KafkaApplication</mainClass> </configuration> </plugin> 我们的示例应用程序是 Spring Boot。 本文假定服务器使用默认配置启动,并且没有更改服务端口。 3、配置 Topic 之前,我们使用命令行工具在 Kafka 中创建主题: $ bin/kafka-topics.sh --create \ --zookeeper localhost:2181 \ --replication-factor 1 --partitions 1 \ --topic mytopic 但随着 Kafka 引入 AdminClient,我们现在可以以编程式创建 topic。

在 Spring Boot 中使用 OpenAI ChatGPT API

1、概览 在本教程中,我们将学习如何在 Spring Boot 中调用 OpenAI ChatGPT API。我们将创建一个 Spring Boot 应用程序,通过调用 OpenAI ChatGPT API 来生成对提示的回复。 2、OpenAI ChatGPT API 在开始本教程之前,让我们先了解一下本教程中将使用的 OpenAI ChatGPT API。我们将调用 create chat completion API 来生成对提示的回复。 2.1、API 参数和认证 让我们来看看 API 强制的请求参数: model - 是我们将向其发送请求的模型版本。该模型有几个版本。我们将使用 gpt-3.5-turbo 模型,它是 该模型的最新公开版本。 messages - 发送给模型的提示。每条 message 都需要两个字段:role 和 content。role 字段指定信息的发送者。在请求中是 user,在回复中是 assistant。content 字段是实际的消息。 API 调用需要认证,我们需要生成一个 OpenAI API key。在调用 API 时在 Authorization 头中设置该 key。 cURL 格式的请求示例如下: $ curl https://api.openai.com/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -d '{ "model": "gpt-3.

在 Spring 6 中使用虚拟线程(Virtual Threads)

1、简介 在这个简短的教程中,我们将了解如何在 Spring Boot 中使用虚拟线程(Virtual Threads)。 虚拟线程是 Java 19 的 预览特性,这意味着它们将在未来 12 个月内被纳入 JDK 的正式版本中。虚拟线程最初是由 Loom 项目引入的,在 Spring 6 中,开发人员可以一睹为快了。 首先,我们将了解 “平台线程” 与 “虚拟线程” 的主要区别。接下来,我们将使用虚拟线程从头开始构建一个 Spring-Boot 应用。最后,我们会进行一个测试,测试 web 应用的吞吐量提升了多少。 2、虚拟线程和平台线程 主要区别在于,虚拟线程在运行周期内不依赖操作系统线程:它们与硬件脱钩,因此被称为 “虚拟”。这种解耦是由 JVM 提供的抽象层赋予的。 虚拟线程的运行成本远低于平台线程。它们消耗的内存要少得多。这就是为什么我们可以创建数百万个虚拟线程而不会出现内存不足的问题,而标准平台(或内核)线程只能创建数百个。 从理论上讲,这赋予了开发人员一种超级能力:无需依赖异步代码即可管理高度可扩展的应用程序。 3、在 Spring 6 中使用虚拟线程 从 Spring Framework 6(和 Spring Boot 3)开始,虚拟线程功能正式全面可用,但虚拟线程是 Java 19 的预览特性。这意味着我们需要告诉 JVM 我们想在应用程序中启用虚拟线程。由于我们使用 Maven 构建应用程序,因此要确保在 pom.xml 中包含以下代码: <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>19</source> <target>19</target> <compilerArgs> --enable-preview </compilerArgs> </configuration> </plugin> </plugins> </build> 从 Java 的角度来看,要使用 Apache Tomcat 和虚拟线程,我们需要一个简单的配置类和几个 Bean: