Spring Boot 3 和 Observability(可观察性)

1、概览 在本文中,我们将学习如何在 Spring Boot 3 配置可观察性(observability)。可观察性是一种仅通过外部输出来衡量系统内部状态的能力。 此外,我们必须注意 Spring Boot 2(Spring 5)和 Spring Boot 3(Spring 6)之间的重大变化。Spring 6 引入了 Spring Observability,这是一项建立在 Micrometer 和 Micrometer Tracing(原 Spring Cloud Sleuth)基础上的新举措。它更适合使用 Micrometer 高效记录应用指标,并通过 OpenZipkin 的 Brave 或 OpenTelemetry 等 provider 实现追踪。Spring Observability 优于“基于代理的可观察性解决方案”,因为它能在原生编译的 Spring 应用程序中无缝运行,并能更有效地提供更好的信息。 我们只介绍有关 Spring Boot 3 的详细信息。如果要从 Spring Boot 2 迁移,可以在这里找到详细说明。 2、Micrometer Observation API Micrometer 是一个独立于供应商中立的“应用度量 facade”的项目。它定义了 meter、rate aggregation、counter、gauge 和 timer 等概念,每个供应商都可以根据自己的概念和工具进行调整。其中一个核心部分是 Observation API,它允许对代码进行一次性的仪表化,并具有多种优势。 仪表化是指在代码中添加监测点或仪表,以便收集关于代码执行过程的信息。这些监测点可以是特定的观测点或代码片段,用于捕获代码的执行路径、变量状态、函数调用和其他相关信息。这些信息对于代码性能分析、调试和优化非常有用。 它是 Spring Framework 多个部分的依赖项之一,因此我们需要了解这个 API,才能理解 Spring Boot 中的观察功能是如何工作的。我们可以通过一个简单的示例来实现这一点。

Spring Boot 整合 Apache Pulsar 入门指南

1、概览 Apache Pulsar 是一个分布式发布/订阅消息系统。Apache Pulsar 提供的功能与 Apache Kafka 类似,但 Pulsar 的目标是克服 Kafka 的高延迟、低吞吐量、难以扩展和地理复制等局限性。在处理需要实时处理的大量数据时,Apache Pulsar 是一个不错的选择。 在本教程中,我们将学习如在 Spring Boot 应用中整合 Apache Pulsar,以及如何使用 Pulsar 的 Spring Boot Starter 提供的 PulsarTemplate 和 PulsarListener。我们还将了解如何根据自己的需求修改它们的默认配置。 2、Maven 依赖 首先,先根据 Apache Pulsar 简介中所述,运行独立的 Apache Pulsar 服务器。 然后,将 spring-pulsar-spring-boot-starter 库添加到项目中: <dependency> <groupId>org.springframework.pulsar</groupId> <artifactId>spring-pulsar-spring-boot-starter</artifactId> <version>0.2.0</version> </dependency> 3、PulsarClient 要与 Pulsar 服务器交互,我们需要配置一个 PulsarClient。默认情况下,Spring 会自动配置一个 PulsarClient,连接到 localhost:6650 上的 Pulsar 服务器: spring: pulsar: client: service-url: pulsar://localhost:6650 我们可以更改配置,从自定义的地址上建立连接。 要连接到 ssl 下的 pulsar 服务器 ,可以使用 “pulsar+ssl” 代替 “pulsar”。我们还可以通过在 application.

使用 Spring Boot 创建 Fat Jar 应用

在本指南中,我将向你展示如何使用 Spring Boot 创建 Fat Jar。我们将一起构建一个简单的 “UsersMicroservice”,然后将其打包到 Fat Jar 中。如果你是新手,也不用担心,我会一步一步地指导你,并回答你在使用过程中遇到的各种问题。 Fat JAR 是啥? Fat JAR 通常也称为 uber-JAR,是一种 Java 归档 (JAR) 文件,它不仅包括应用程序的编译源代码,还包括运行应用程序所需的所有依赖项和资源。这些依赖项可能包括库、框架,甚至是嵌入式服务器,如 Tomcat 或 Jetty,这些通常在 Spring Boot 应用中使用。 换句话说,Fat JAR 是一个独立可直接运行的软件包。与普通 JAR 文件不同的是,普通 JAR 文件在运行应用程序时可能需要在 classpath 中存在外部依赖,而 Fat JAR 文件则完全自给自足,可以在任何已安装 Java 虚拟机(JVM)的系统上运行,无需安装或设置任何额外的依赖。 为什么使用 Fat JAR? 使用 Fat JAR 有几个好处: 简单: 由于 Fat JAR 包已经含运行应用程序所需的所有内容,因此它简化了部署过程。没有在部署环境中设置和管理外部依赖的负担。 可移植性: 你可以在任何支持 JVM 的平台上运行 fat JAR。这使得它具有极高的可移植性,非常适合各种环境,包括不同的开发、测试、暂存和生产设置。 微服务架构: Fat JAR 在微服务架构中尤其有用。在这种架构风格中,每个微服务通常都是一个独立的应用程序,可以独立开发、部署和扩展。将每个微服务打包为 Fat JAR,可以方便地分别管理和部署每个服务。 一致性: 将应用程序打包为 fat JAR 时,可以确保在构建和运行应用程序时使用同一套依赖。这有助于避免在构建和运行时使用不同版本的依赖时可能出现的问题。 尽管有这些优点,但也要注意 fat JAR 的缺点。fat JAR 可能比普通 JAR 大得多,这会减慢构建和启动速度,并占用更多资源。此外,如果同一系统中的多个 fat JAR 使用相同的依赖,这可能会导致冗余,因为每个 JAR 都包含每个依赖的副本。

Spring Boot 3:使用 HTTP API 的 Problem Details 进行错误响应

Spring Framework 6 实现了 “Problem Details for HTTP APIs(HTTP API 的问题细节规范)”(RFC 7807)。在本文中,我们将学习如何在 SpringBoot 3 REST API(使用 Spring Framework 6)中处理异常,并使用 ProblemDetails API 提供错误响应。 假设我们有以下 REST API 端点,用于创建书签(bookmark)和按 ID 获取书签。 @RestController @RequestMapping("/api/bookmarks") @RequiredArgsConstructor public class BookmarkController { private final BookmarkService service; @PostMapping public ResponseEntity<Bookmark> save(@Valid @RequestBody Bookmark payload) { Bookmark bookmark = new Bookmark(null, payload.title(), payload.url(), Instant.now()); return ResponseEntity.status(HttpStatus.CREATED).body(service.save(bookmark)); } @GetMapping("/{id}") public ResponseEntity<Bookmark> getBookmarkById(@PathVariable Long id) { return service.getBookmarkById(id) .map(ResponseEntity::ok) .orElseThrow(() -> new BookmarkNotFoundException(id)); } } 而且,BookmarkNotFoundException 是一种典型的 RuntimeException,具体如下:

使用 API Key 和 Secret 保护 Spring Boot API

1、概览 安全在 REST API 开发中起着至关重要的作用。不安全的 REST API 可以直接访问后端系统的敏感数据。因此,企业需要关注 API 的安全性。 Spring Security 提供了各种机制来保护我们的 REST API。其中之一就是 API key。API key 是客户端在调用 API 时提供的 Token。 在本教程中,我们将讨论 Spring Security 中基于 API key 的身份认证的实现。 2、REST API 安全 Spring Security 可用于保护 REST API。REST API 是无状态的。因此,它们不应使用会话或 cookie。相反,它们应该使用 Basic authentication、API key、JWT 或基于 OAuth2 的 token 来确保安全。 2.1、Basic Authentication Basic authentication 是一种简单的身份认证方案。客户端发送 HTTP 请求时,Authorization 包含 Basic 字样,后面跟一个空格和一个 Base64 编码的字符串 username:password。Basic authentication 只有在使用 HTTPS/SSL 等其他安全机制时才被认为是安全的。 2.2、OAuth2 OAuth2 是 REST API 安全性的事实标准。它是一个开放的身份认证和授权标准,允许资源所有者通过 access token 权客户端访问私有数据。

Eureka Server 集群部署教程

在本教程中,你将学习到如何在本地计算机上设置 Eureka Cluster(集群)。虽然本文是在本地计算机上设置的 Eureka Cluster,但你仍然可以学到如何让 Eureka 在远程服务器上运行。 什么是 Eureka 服务器集群? Eureka 服务器集群又称 Eureka 节点感知(Peer Awareness)系统,是一组相互通信的 Eureka 服务器。不过,这不是普通的服务器群。它们可以相互通信,共享注册服务的相关信息。这意味着即使其中一台服务器宕机,其他服务器仍能提供必要的服务信息,确保高可用性和容错性。这是一项关键功能,使 Eureka 服务器集群成为大型系统的绝佳选择,在这种系统中,宕机的代价可能很高。 现在,你可能会问,为什么我们需要这样的设置。好吧,把它想象成一个图书管理员团队,他们总是相互通报庞大图书馆中书籍的最新情况。如果其中一个人不在,其他人仍然可以为你找到你要的书提供指导。同样,Eureka 服务器集群可确保你的微服务始终能找到彼此,即使在服务器出现故障的情况下也是如此。正是它们的团队合作使你的微服务架构变得稳健而富有弹性。 在接下来的章节中,我将指导你建立自己的 Eureka 服务器集群。 创建 Eureka Server 项目 我们首先要做的是创建一个新的 Spring Boot 项目。为此,我们将使用 Spring Initializr 来快速创建我们的项目。创建项目时,我们需要确保添加一个名为 Eureka Server 的重要依赖项。该依赖将把我们的普通 Spring Boot 项目转变为 Eureka Server。如果你现在还不清楚如何操作,也不用担心。我们将在下一步了解详情。 必须的 Maven 依赖 如果使用 Spring Initializr 工具创建了项目,并添加了 Eureka Server 依赖,则应在项目的 pom.xml 文件中看到以下依赖。 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> 在我的案例中,完整的 pom.xml 文件是这样的: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.

Spring Data JPA 中的分页和排序

1、概览 当我们数据库中的记录数量较多的时候,一般不会一次性检索出所有记录,通常会通过分页的方式展现。 此外,我们还经常需要在分页时根据某些条件对数据进行排序。 在本教程中,我们将学习如何使用 Spring Data JPA 轻松实现分页和排序。 2、创建实体 首先,假设我们有一个 Product 实体作为 domain 类: @Entity public class Product { @Id private long id; private String name; private double price; // 构造函数, getter 和 setter } 我们的每个 Product 实例都有一个唯一的标识符: id、name 和 price。 3、创建 Repository 要访问我们的 Product,我们需要一个 ProductRepository: public interface ProductRepository extends PagingAndSortingRepository<Product, Integer> { List<Product> findAllByPrice(double price, Pageable pageable); } 通过让它继承 PagingAndSortingRepository,我们可以使用,用于分页和排序的 findAll(Pageable pageable) 和 findAll(Sort sort) 方法。 相反,我们也可以选择继承 JpaRepository,因为它也继承了 PagingAndSortingRepository。

Spring Boot 3 中对 Docker Compose 的支持

1、概览 Spring Boot 3 具有一些新功能,比如将我们的应用程序构建为 GraalVM Native Image(原生镜像)。另一个相关支持是 Docker Compose。 在本教程中,我们将了解如何将 Docker Compose 工作流与 Spring Boot 3 整合。 2、Spring Boot 3 的 Docker Compose Support 提供了什么? 通常,我们会根据 docker-compose.yml 运行 docker-compose up 来启动和 docker-compose down 来停止我们的容器。现在,我们可以将这些 Docker Compose 命令委托给 Spring Boot 3。当 Spring Boot 应用程序启动或停止时,它也会管理我们的容器。 此外,它还内置了对多种服务的管理,如 SQL 数据库、MongoDB、Cassandra 等。因此,我们可能不需要在 application 资源文件中重复配置 class 或 properties。 最后,我们会看到如何在该支持中使用自定义 Docker 镜像和 Docker Compose profiles 。 3,设定 我们需要 Docker Compose 和 Spring Boot 3 来探索这种新的支持。 3.1、Docker Compose Docker Compose 需要已安装的 Docker 引擎。它们很容易安装,不过根据操作系统的不同可能会有差异。

在 Spring Boot 3 中使用 Java Record

Record 在 Java 14 中作为预览功能引入,并在 JDK 16 中成为标准功能。Record 是不可变数据类(data class)的简洁表示。 在使用 Record 之前,我们通常是这样创建不可变 class 的。 import java.util.Objects; class Person { private final Long id; private final String name; public Person(Long id, String name) { this.id = id; this.name = name; } public Long getId() { return this.id; } public String getName() { return this.name; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() !

Java IllegalStateException: “getInputStream() has already been called for this request”

1、介绍 有时,当我们在 Java Web 应用程序中调用 ServletRequest 接口的 getReader() / getInputStream()方法时,可能会出现IllegalStateException 异常,异常信息为:“getInputStream() has already been called for this request”。 在本教程中,我们将了解出现这种异常的原因和解决方法。 2、问题与原因 Java Servlet 规范,用于用 Java 构建 Web 应用程序。它定义了 ServletRequest / HttpServletRequest 接口,以及 getReader() 和 getInputStream() 方法,用于从 HTTP 请求中读取数据。 getReader() 方法以字符数据形式返回请求体,而 getInputStream() 方法则以二进制数据形式返回请求体。 getReader() 和 getInputStream() 的 Servlet API 文档强调,它们不能同时使用: public java.io.BufferedReader getReader() Either this method or getInputStream may be called to read the body, not both. ... Throws: java.lang.IllegalStateException - if getInputStream() method has been called on this request public ServletInputStream getInputStream() Either this method or getReader may be called to read the body, not both.