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 应用程序时,我们需要考虑三种不同的运行时选项:
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 接口:
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 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 操作。
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 等信息会自动生成。
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。
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.
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:
在调用第三方Api服务的时候,如果涉及到文件上传,就需要自己通过 Http 客户端发起 Multipart 请求来上传文件。
在 Spring 应用中比较流行的 Http 客户端就是 RestTemplate。本文将会指导你如何用 RestTemplate 发起 Multipart 请求来上传文件。
服务端 在服务端创建一个用于测试的 FileUploadController, 它接受来自客户端的 Multipart 文件请求,并且响应文件的相关信息。
package cn.springdoc.demo.controller; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import org.springframework.util.StreamUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import jakarta.servlet.http.HttpServletResponse; @RestController @RequestMapping("/upload") public class FileUploadController { private static final Logger log = LoggerFactory.getLogger(FileUploadController.class); /** * 文件上传 * @param file * @param response * @return * @throws IOException */ @PostMapping(consumes = MediaType.
1、概览 自注入是指 Spring Bean 将自身作为依赖注入。它使用 Spring 容器获取自身的引用,然后使用该引用执行某些操作。
在这个简短的教程中,我们将了解如何在 Spring 中使用自注入。
2、自注入的场景 自注入最常见的用例是在需要将切面应用于自引用的方法或类时,绕过 Spring AOP 的限制
假设我们有一个执行某些业务逻辑的 service 类,需要调用自身的一个方法作为该逻辑的一部分:
@Service public class MyService { public void doSomething() { // ... doSomethingElse(); } @Transactional public void doSomethingElse() { // ... } } 不过,当我们运行应用程序时,可能会发现 @Transactional 并未生效。这是因为 doSomething() 方法直接调用了 doSomethingElse(),从而绕过了 Spring 代理。
为了解决这个问题,我们可以使用自注入获取 Spring 代理的引用,然后通过该代理调用方法。
3、使用 @Autowired 自注入 在 Spring 中,我们可以通过在 Bean 的字段、构造器参数或 setter 方法上使用 @Autowired 注解来进行自注入。
下面是一个在字段上使用 @Autowired 的示例:
@Component public class MyBean { @Autowired private MyBean self; public void doSomething() { // 在这里使用 self 引用 } } 通过构造器参数自注入。