在本章节教程中,我将介绍我们在实现创建和更新 API 端点时应遵循的一些最佳实践。
Spring Boot REST API 最佳实践 - 第一章:实现 Get Collection API Spring Boot REST API 最佳实践 - 第二章:实现 Create 和 Update API(本文) Spring Boot REST API 最佳实践 - 第三章:实现 FindById 和 DeleteById API Spring Boot REST API 最佳实践 - 第四章:REST API 的异常处理 本文是 Spring Boot REST API 最佳实践 - 第一章 的续章。因此,如果你还没有阅读,请先阅读第一章。我们将在第一章中实现的代码基础上构建 API。
你可以在此 GitHub 仓库中找到本教程中的示例代码。
实现 POST /api/bookmarks API 端点 我们可以考虑按如下方式实现 POST /api/bookmarks API 端点:
package com.sivalabs.bookmarks.api.controllers; import com.
在本章节教程中,我将介绍我们在实现 REST API 时应遵循的一些最佳实践,和开发人员常犯的一些错误以及如何避免这些错误。
Spring Boot REST API 最佳实践 - 第一章:实现 Get Collection API(本文) Spring Boot REST API 最佳实践 - 第二章:实现 Create 和 Update API Spring Boot REST API 最佳实践 - 第三章:实现 FindById 和 DeleteById API Spring Boot REST API 最佳实践 - 第四章:REST API 的异常处理 在第一章中,我们将实现第一个 API 端点,即获取资源列表。我们将了解开发人员常犯的一些错误以及如何避免这些错误。
创建 Spring Boot 应用 首先,访问 https://start.springboot.io,选择 Spring Web、Validation、Spring Data JPA、PostgreSQL Driver、Flyway Migration 和 Testcontainers starter,创建一个 Spring Boot 应用程序。
我们的示例应用及其简单,但却是按真实应用程序中遵循的相同实践进行操作。
本教程中的示例代码,可以在 GitHub 中找到。
1、概览 单例对象经常被开发人员使用,因为应用程序中的许多对象都需要重复使用一个单例。在 Spring 中,我们可以通过 使用 Spring 的单例 Bean 或自己实现单例设计模式 来创建单例对象。
在本教程中,我们将首先了解单例设计模式及其线程安全的实现。然后,我们将了解 Spring 中的 Singleton Bean Scope,并将 singleton Bean 与使用单例设计模式创建的对象进行比较。
最后,我们将介绍一些可行的最佳实践。
本文中的 “Singleton Bean”,即“单例 bean”。
2、单例设计模式 单例是 “GoF” (si人帮?)于 1994 年发布的最简单的设计模式之一。它被归类于创建模式,因为单例提供了一种只创建一个实例的方法。
2.1、模式定义 单例模式是指由一个类负责创建对象,并确保只创建一个实例。我们经常使用单例来共享状态或减少创建多个对象的成本。
单例模式实现可以确保只创建一个实例:
通过实现单个私有构造函数来隐藏所有构造函数。 仅在实例不存在时创建实例,并将其存储在私有静态变量中。 使用公共静态 getter 方法访问该单例。 让我们看看几个使用单例对象的类的示例:
在上面的类图中,我们可以看到多个服务如何使用只创建一次的同一个单例。
2.2、懒加载 单例模式实现通常使用懒加载来延迟实例创建(也称为“懒汉式”),直到第一次实际需要时才创建。为了确保延迟实例化,我们可以在首次调用静态 getter 方法时创建实例:
public final class ThreadSafeSingleInstance { private static volatile ThreadSafeSingleInstance instance = null; private ThreadSafeSingleInstance() {} public static ThreadSafeSingleInstance getInstance() { if (instance == null) { synchronized(ThreadSafeSingleInstance.class) { if (instance == null) { instance = new ThreadSafeSingleInstance(); } } } return instance; } // 标准的 getter 方法 } 在多线程应用中,延迟加载可能会导致并发问题。因此,我们还应用了双重检查锁,以防止不同线程创建多个实例。
1、概览 在本教程中,我们将学习如何将 Spring Boot 应用迁移到 3.0 版本。当前所使用的 Spring Boot 版本是 2.7,并且 Java 版本是 17。
2、核心的变化 Spring Boot 3.0 是该框架的一个重要里程碑,对其核心组件进行了多项重要修改。
2.1、配置属性 部分属性的修改:
spring.redis 已移至 spring.data.redis。 spring.data.cassandra 已移至 spring.cassandra。 移除了spring.jpa.hibernate.use-new-id-generator。 server.max.http.header.size 已移至 server.max-http-request-header-size。 移除了对 spring.security.saml2.relyingparty.registration.{id}.identity-provider 的支持。 要识别这些属性,我们可以在 pom.xml 中添加 spring-boot-properties-migrator:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-properties-migrator</artifactId> <scope>runtime</scope> </dependency> 最新版本的 spring-boot-properties-migrator 可从 Maven Central 获取。
该依赖会在启动时生成并打印一份报告,列出已废弃的属性名称,并在运行时临时迁移这些属性。
2.2、Jakarta EE 10 新版 Jakarta EE 10 对 Spring Boot 3 的相关依赖进行了更新:
Servlet 规范更新至 6.0。 JPA 规范更新至 3.1。 因此,如果我们未通过 spring-boot-starter 来自动管理这些依赖的版本,我们就应该手动更新它们。
在之前的 Spring Boot JdbcTemplate 教程 中,我们见识了如何使用 schema.sql 和 data.sql 脚本初始化数据库。这对于演示项目可能有用,但对于实际应用,我们应该使用数据库迁移工具。
Flyway 是最流行的基于 Java 的数据库迁移工具。可以将 Flyway 作为独立库,或使用 flyway-maven-plugin 或使用 Flyway Gradle 插件进行数据库迁移。
Spring Boot 提供了开箱即用的支持,用于 Flyway 数据库迁移。让我们看看如何创建一个使用 Spring Data JPA 与 PostgreSQL 数据库交互,并使用 Flyway 实现数据库迁移的 Spring Boot 应用。
首先,访问 https://start.springboot.io/,选择 Spring Web、Spring Data JPA、PostgreSQL Driver、Flyway Migration 和 Testcontainers starter,创建 Spring Boot 应用程序。
创建 Flyway 迁移脚本 Flyway 遵循 V<VERSION>__<DESCRIPTION>.sql 命名约定来命名其版本化的迁移脚本。让我们在 src/main/resources/db/migration 文件夹下添加以下两个迁移脚本。
V1__create_tables.sql:
create table bookmarks ( id bigserial not null, title varchar not null, url varchar not null, created_at timestamp, primary key (id) ); V2__create_bookmarks_indexes.
Spring Boot 最具特色的功能就是使用嵌入式服务器,可以把应用构建为一个独立、可执行的 jar,这极大地方便了部署。但是仍有人希望把应用打包为 WAR 包,部署在外部的 Servlet 容器(Tomcat、Jetty 等)中运行。
本文将会指导你如何更改 Spring Boot 的打包方式为 War,并且部署到外部服务器中(Servlet 3.x +)。
Spring Boot 打包为 War 包的步骤 1、修改打包方式 <packaging>war</packaging> 修改 packaging 节点值为 war。Maven 工程默认打包方式为 jar,如果你的 pom.xml 中没有 packaging 节点,则需要手动设置。
2、修改 Servlet 容器的 scope <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> 由于我们会使用外部的 Tomcat,所以需要主动把嵌入式容器 spring-boot-starter-tomcat 依赖的 scope 声明为 provided,表示该依赖只用于编译、测试。
3、修改启动类,继承 SpringBootServletInitializer package cn.springdoc.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; @SpringBootApplication public class DemoApplication extends SpringBootServletInitializer{ public static void main(String[] args) { SpringApplication.
酝酿已久,我们终于可以创建使用 Spring Boot(3.2)和 Java 21 虚拟线程(Project Loom)的 GraalVM 原生镜像了!
这一切有什么意义呢?Project Loom 和 GraalVM 原生镜像各自都具有引人注目的运行时特性。我已经等了很久,终于等到了它们的融合!让我们依次唠唠。
GraalVM 原生镜像 GraalVM 是一个 OpenJDK 发行版,提供了一些额外的实用工具,其中包括一个名为 native-image 的工具,它可以对你的代码进行提前编译(AOT)。我们在这里不会详细介绍所有的实用功能,基本上它会对你的代码进行优化,去除你不需要的部分,然后将剩余的代码编译成针对特定操作系统和架构的原生代码,运行速度非常快。结果令人惊叹,类似于编译 C 或 Go 程序所得到的结果。生成的可执行文件在启动时几乎没有延迟,并且在运行时占用的内存要少得多。想象一下,能够部署现有的 Spring Boot 应用程序,并且它只占用几十兆字节的内存,并在几百毫秒内启动。现在,这是可能的。只需运行 ./gradlew nativeCompile 或 ./mvnw -Pnative native:compile,即可。自 2022 年 11 月 Spring Boot 3.0 发布以来,Spring Boot 已经支持在生产环境中使用 GraalVM 原生镜像。
Project Loom Project Loom 为 JVM 引入了透明的 Fiber(纤程,也成为协程、虚拟线程)。就目前而言,在 Java 20 或更早的版本中,IO 是阻塞的。调用 InputStream#read() 可能需要等待下一个字节的到达。在 java.io.File IO中,很少会有太多延迟。然而,在网络中,你真的无法确定。客户端可能会断开连接。客户端可能会经过一个隧道。同样,很难说。在此期间,程序流程被阻塞在执行线程上。在下面的代码片段中,我们无法知道何时会看到打印出来的单词 after。可能是从现在开始的纳秒级时间,也可能是从现在开始的一周后。它是阻塞的。
InputStream in = ... System.out.println("before"); int next = in.
1、概览 Springfox 和 SpringDoc 这两个工具简化了 Swagger API 文档的生成和维护。
在本教程中,我们将了解如何在 Spring Boot 应用中更改 Swagger-UI URL 前缀。
2、使用 Springdoc 时更改 Swagger UI URL 前缀 首先,我们可以看看 如何使用 OpenAPI 3.0 生成 REST API 文档。
根据上述教程,我们需要添加如下 SpringDoc 的依赖:
<dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.0.2</version> </dependency> swagger-ui 的默认 URL 是 http://localhost:8080/swagger-ui.html。
比方说,我们要增加 /myproject 前缀,接下来让我们看看自定义 swagger-UI URL 的两种方法。
2.1、application.properties 我们可以在 application.properties 文件中添加以下属性来修改 swagger-UI URL:
springdoc.swagger-ui.disable-swagger-default-url=true springdoc.swagger-ui.path=/myproject 2.2、配置类 我们也可以通过配置类来实现:
@Component public class SwaggerConfiguration implements ApplicationListener<ApplicationPreparedEvent> { @Override public void onApplicationEvent(final ApplicationPreparedEvent event) { ConfigurableEnvironment environment = event.
1、概览 在本教程中,我们将演示如何使用 Swagger 注解使我们的文档更具描述性。我们会学习如何为 API 的不同部分(如方法、参数、响应等)添加描述,以及如何添加请求/响应示例。
2、项目设置 我们将创建一个简单的 Product API,提供创建和获取 product 的方法。
要从头开始创建 REST API,我们可以按照 Spring 文档中的教程 使用 Spring Boot 创建 RESTful Web 服务。
下一步是为项目设置依赖和配置。我们可以按照 本文 中的步骤使用 Spring REST API 设置 Swagger 2
3、创建 API 创建 Product API 并检查生成的文档。
3.1、Model 定义 Product 类:
public class Product implements Serializable { private long id; private String name; private String price; // 省略 get/set 构造函数 } 3.2、Controller 定义两个 API 方法:
@RestController @Tag(name = "Products API") public class ProductController { @PostMapping("/products") public ResponseEntity<Void> createProduct(@RequestBody Product product) { //creation logic return new ResponseEntity<>(HttpStatus.
1、概览 在本教程中,我们将探讨如何使用 Serverless Application Model (SAM) 框架将 Spring Boot 应用程序部署到 AWS Lambda。
这种方法有助于将现有的 API 服务器迁移到 serverless 上。
通过这种方法,我们可以利用 AWS Lambda 的可扩展性和按执行付费的定价模式,高效、经济地运行我们的应用程序。
2、理解 Lamdba AWS Lambda 是亚马逊网络服务(AWS)提供的 serverless 计算服务。它允许我们在无需配置或管理服务器的情况下运行代码。
Lambda 函数与传统服务器的主要区别之一是,Lambda 函数由事件驱动,生命周期很短。
Lambda 函数不像服务器那样持续运行,而是只在响应特定事件时才运行,例如 API 请求、队列中的消息或上传到 S3 的文件。
我们应该注意到,lambda 在处理第一个请求时需要一定的时间来启动。这就是所谓的 “冷启动”。
如果下一个请求在短时间内出现,可以使用相同的 lambda 运行时,这被称为 “热启动”。如果同时出现多个请求,则会启动多个 Lambda 运行时。
与 Lambda 理想的毫秒级启动时间相比,Spring Boot 的启动时间相对较长,因此我们会讨论这对性能的影响。
3、项目设置 我们通过修改 pom.xml 和添加一些配置来迁移现有的 Spring Boot 项目。
Spring Boot 支持的版本有 2.2.x、2.3.x、2.4.x、2.5.x、2.6.x 和 2.7.x。
3.1、Spring Boot API 示例 我们的应用程序由一个简单的 API 组成,它可以处理对 api/v1/users 端点的任何 GET 请求: