Spring Boot 3.3.0 正式发布

从 Spring Boot 3.2 进行升级 Jersey Observability(可观察性) Micrometer 1.13 已放弃对 Jersey 的支持,转而使用 Jersey 的 jersey-micrometer 模块。如果你的应用使用 Jersey 指标,请在升级时添加对 org.glassfish.jersey.ext:jersey-micrometer 依赖。 为了支持 Jersey 的可观察下,MetricsApplicationEventListener 已被替换为 ObservationApplicationEventListener。如果你之前使用 JerseyTagsProvider 自定义标签(Tag),现在需要实现一个 JerseyObservationConvention bean 来完成此功能。 删除了 Dropwizard 指标的 Dependency Management Dropwizard Metrics 的 Dependency management 理已删除。Spring Boot 并不直接依赖于 Dropwizard Metrics,因此不需要特定的版本。如果你的应用直接依赖于 Dropwizard Metrics,请更新你的构建配置,以指定满足其需求的版本。 Prometheus Client 1.x Spring Boot 3.3 包含对 Prometheus 客户端 1.x 的支持。该版本的客户端包含一些破坏性更改,例如对导出指标名称的更改。在 Prometheus 维护者添加该支持之前,1.x 客户端不支持使用 Prometheus Push Gateway。 如果你想继续使用 0.x 版本的 Prometheus 客户端,请从依赖中移除 io.micrometer:micrometer-registry-prometheus,并添加 io.

使用 Prometheus 监控 Spring Boot 应用

1、概览 在软件开发这个要求严苛的领域中,确保应用在在部署到生产环境后能够以最佳性能和可靠性运行是至关重要的。 本文将带你了解如何在 Spring Boot 应该中整合 Prometheus,以及如何通过基本配置和复杂配置丰富我们的监控策略。 2、Prometheus 是什么? Prometheus 是一个开源项目,旨在深入挖掘我们的应用程序数据,通过创建过滤层来收集和分析从最简单到最复杂的所有内容。它不仅仅关乎数字和图表,而且通过其高级查询语言和时间序列数据能力,帮助我们理解应用程序的运行状况。 集成 Prometheus 使我们能够在问题发生之前就发现问题,对系统进行微调,确保应用程序以最佳性能运行,最终为用户带来更好的体验 - 方便、快捷、可靠。 3、开始在 Spring Boot 中使用 Prometheus 将 Prometheus 与 Spring Boot 应用程序整合后,就能以 Prometheus 可以理解和抓取的格式公开应用指标,从而有效地进行监控。这一过程包括两个主要步骤:向项目添加必要的依赖项,以及配置应用以公开指标。 3.1、添加依赖 首先,将 Spring Boot Actuator 和 Micrometer Prometheus Registry 添加到项目的依赖中。Actuator 提供了一系列内置端点,用于显示运行应用的性能信息,如健康状况、指标等。Micrometer Prometheus registry 会将这些指标格式化为 Prometheus 可读格式。 将依赖添加到 Maven 项目的 pom.xml 文件中: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> 如果使用的是 Gradle,则应在 build.gradle 文件中添加如下内容: implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'io.micrometer:micrometer-registry-prometheus' 3.2、配置应用 添加依赖后,下一步就是配置 Spring Boot 应用,使其暴露 Prometheus 指标端点。这需要更新项目中的 application.

清除 JPA/Hibernate 中托管的实体

1、概览 本文将带你了解 JPA 是如何托管实体的,以及 Persistence Context(持久化上下文)由于外部变化而无法返回最新数据的情况。 2、Persistence Context 每个 EntityManager 都与一个 Persistence Context 相关联,该上下文在内存中存储所管理的实体。每当通过 EntityManager 对实体执行任何数据操作时,该实体就会变成由 Persistence Context 管理的实体。 当再次检索实体时,JPA 会从 Persistence Context 返回托管实体,而不是从数据库中获取。这种缓存机制有助于提高性能,而无需从数据库中重复获取相同的数据。 Persistence Context 在 JPA 中也被称为一级(first-level,L1)缓存。 3、Demo 设置 首先,创建一个简单的实体类: @Entity @Table(name = "person") public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; // 构造函数、Getter、Setter 方法省略 } 接下来,创建一个 Person 实体并将其持久化到数据库中: EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); Person person = new Person(); person.setName("David Jones"); entityManager.persist(person); transaction.

Spring Security 6.3.0 发布

Spring Security 6.3.0 正式发布! 6.3 版本带来了几个引人注目的特性,如下: 长期的 JDK 序列化向后兼容性 新的方法安全注解和功能 密码受损检查 支持 OAuth 2.0 令牌交换 该版本将包含在即将发布的 Spring Boot 3.3 GA 版本中。 ⭐ 新特性 为 OAuth2AuthorizedClientId 添加 Getter #13648 为 JwtDecoders 添加超时默认值 #14890 文档:添加了将 GrantedAuthorityDefaults 声明为基础架构 Bean 的提示 #15065 改进全局身份认证(Global Authentication)的日志记录 #14711 文档小修正 #15043 需要对使用 Kotlin DSL 的导入进行微小的文档更新 #14969 OAuth2 客户端身份认证文档不完整 #14982 校对 CasAuthenticationFilter 文档 #14883 将 “Spring Boot 2.x” 替换为 “Spring Boot” #14919 简化禁用 “application/x-www-form-urlencoded” 编码 Client ID 和 Secret#14859 支持为依赖方注册元素指定标识符 #14487 更新 6.

JPA 中实体的继承与组合

1、简介 继承(Inheritance)和组合(Composition)是面向对象编程(OOP)中的两个基本概念,我们也可以在 JPA 中利用它们进行数据建模。在 JPA 中,继承和组合都是对实体间关系进行建模的技术,但它们代表的是不同类型的关系。本文将带你了解这两种方法及其影响。 2、JPA 中的继承 继承是一种 “is-a” 关系,即子类继承超类的属性和行为。这允许子类从超类继承属性和方法,从而促进了代码的重用。JPA 提供了几种策略来模拟实体与其对应的数据库表之间的继承关系。 2.1、单表继承(STI) 单表继承(Single Table Inheritance,STI)将所有子类映射到单个数据库表中。通过利用 区分列 来区分子类实例,这简化了 Schema 管理和查询执行过程。 首先,使用 @Entity 注解将 Employee 实体类定义为超类。接下来,将继承策略设置为 InheritanceType.SINGLE_TABLE,这样所有子类都会映射到同一个数据库表*。 然后,使用 @DiscriminatorColumn 注解来指定 Employee 类中的 区分列。该列用于区分单个表中不同类型的实体。 示例如下,使用 name = "employee_type" 将列名称指定为 employee_type,并使用 discriminatorType = DiscriminatorType.STRING 表示列包含字符串值: @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "employee_type", discriminatorType = DiscriminatorType.STRING) public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // Get / Set 方法省略 } 对于每个子类,使用 @DiscriminatorValue 注解来指定与该子类相对应的 区别列 的值。在本例中,我们使用 manager 和 developer 分别作为 Manager 和 Developer 子类的 区别值:

JPA 级联保存实体中的子实体

1、概览 本文将带你了解 JPA 如何自动保存复杂的实体模型(即由父实体和子实体元素组成的复杂模型)以及常见的问题。 2、缺失关系注解 我们可能会忽略的第一件事就是添加关系注解。 创建一个子实体: @Entity public class BidirectionalChild { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; //Get/Set 方法省略 } 创建一个包含 List<BidirectionalChild> 的父实体: @Entity public class ParentWithoutSpecifiedRelationship { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private List<BidirectionalChild> bidirectionalChildren; //Get/Set 方法省略 } 如上,bidirectionalChildren 字段上没有注解。尝试用这些实体创建一个 EntityManagerFactory: @Test void givenParentWithMissedAnnotation_whenCreateEntityManagerFactory_thenPersistenceExceptionExceptionThrown() { PersistenceException exception = assertThrows(PersistenceException.class, () -> createEntityManagerFactory("jpa-savechildobjects-parent-without-relationship")); assertThat(exception) .hasMessage("Could not determine recommended JdbcType for Java type 'com.baeldung.BidirectionalChild'"); } 运行测试,出现了异常,无法确定子实体的 JdbcType。单向和双向关系都会出现类似的异常,其根本原因是父实体中缺失 @OneToMany 注解。

Spring Boot 设置日期(Date/LocalDate/LocalDateTime)的 JSON 格式化

1、概览 本文将带你了解如何在 Spring Boot 应用中格式化 JSON Date 字段。 Spring Boot 默认使用 Jackson 作为 JSON 的序列化/反序列化框架。 2、在 Date 字段上使用 @JsonFormat 2.1、设置格式化 我们可以使用 @JsonFormat 注解来格式化特定字段: public class Contact { // 其他字段 @JsonFormat(pattern="yyyy-MM-dd") private LocalDate birthday; @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") private LocalDateTime lastUpdate; // getter/setter 方法省略 } 如上,用了 Java 8 的日期类型,它在处理时间类型时非常方便。birthday 字段只显示日期,而 lastUpdate 字段则包括了时间。 当然,如果需要使用 java.util.Date 等传统类型,也可以同样的方式使用注解: public class ContactWithJavaUtilDate { // 其他字段 @JsonFormat(pattern="yyyy-MM-dd") private Date birthday; @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date lastUpdate; // getter/setter 方法省略 } 最后,来看看使用 @JsonFormat 格式化日期字段后的输出:

配置 Mybatis 的 SQL 查询日志

1、概览 MyBatis 是 Java 界流行的持久化框架,它通过将 SQL 查询映射到 Java 方法来简化数据库操作。 在使用 MyBatis 开发应用时,查看正在执行的 SQL 查询通常对调试很有用,本文将带你了解如何在 MyBatis 中将 SQL 查询日志输出到控制台。 2、支持的日志实现 MyBatis 是一个灵活的框架,可以与各种日志框架集成,包括 SLF4J、Apache Commons Logging、Log4j 2 和 JDK Logging。本文主要关注 Stdout (标准输出,即控制台)日志和 SLF4J。 Stdout 日志在本地功能开发过程中非常有用,它提供了一种简单的调试方法。而 SLF4J 更适合生产应用,它提供了更高级的抽象,可与其他的日志框架无缝集成。 3、在 MyBatis 中配置 Stdout 日志 使用 stdout 记录 MyBatis SQL,可以直接在控制台上查看执行的 SQL 语句。这种方法在开发和调试过程中非常方便。 要启用 MyBatis SQL 的 stdout 日志,需要在应用的 mybatis-config 文件中添加日志设置: <configuration> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> </configuration> 将 logImpl 属性配置为 STDOUT_LOGGING 后,MyBatis 将在执行 SQL 查询时输出原始 SQL 语句、查询参数和查询结果。输出通常包括执行的 SQL、绑定的参数和返回的结果集等详细信息:

Spring AI - 结构化输出

科学处理事物的片段和碎片,并假设存在连续性,而艺术则只关注事物的连续性,假设存在片段和碎片。- 罗伯特·M·皮尔西格 LLM(大型语言模型)生成结构化输出的能力对于依赖于可靠解析输出值的下游应用非常重要。开发人员希望将 AI 模型的结果快速转化为数据类型,如 JSON、XML 或 Java 类,以便传递给应用中的其他函数和方法。 Spring AI Structured Output Converter(结构化输出转换器)有助于将 LLM 输出转换为结构化格式。如下图所示,这种方法围绕 LLM 文本补全端点进行操作: 使用通用的补全 API 从大型语言模型(LLM)生成结构化输出需要对输入和输出进行仔细处理。结构化输出转换器在 LLM 调用之前和之后发挥着关键作用,确保实现所需的输出结构。 在进行 LLM 调用之前,转换器会将格式指令附加到提示中,为模型提供明确的指导,以生成所需的输出结构。这些指令充当蓝图,使模型的响应符合指定的格式。 在 LLM 调用之后,转换器会获取模型的输出文本,并将其转换为结构化类型的实例。转换过程包括解析原始文本输出,并将其映射到相应的结构化数据表示,如 JSON、XML 或特定领域(Domain)的数据结构。 注意,AI 模型不能保证按要求返回结构化输出。它可能不理解提示,也可能无法按要求生成结构化输出。 TIP: 如果你不想深入了解 API 的细节,可以过下一段,直接看 “使用转换器 ”部分。 1、结构化输出 API StructuredOutputConverter 接口定义如下: public interface StructuredOutputConverter<T> extends Converter<String, T>, FormatProvider { } 它以目标结构化类型 T 为参数,结合了 Spring Converter<String, T> 接口和 FormatProvider 接口: public interface FormatProvider { String getFormat(); } 下图说明了通过结构化输出 API 组件的数据流程。

解决 Spring Boot H2 JdbcSQLSyntaxErrorException “Table not found”

1、简介 H2 是一个简单的轻量级内存数据库,Spring Boot 可以自动对其进行配置,使开发人员可以轻松测试数据访问逻辑。 通常情况下,org.h2.jdbc.JdbcSQLSyntaxErrorException 是用于表示与 SQL 语法相关的错误的异常。“Table not found” 表示 H2 无法找到指定的表。 本文将带你了解 H2 抛出 JdbcSQLSyntaxErrorException 异常的原因以及解决办法。 2、示例 既然知道了异常背后的根本原因,来看看如何重现异常。 2.1、H2 配置 Spring Boot 会配置应用使用用户名 sa 和空密码连接到可嵌入的数据库 H2。将这些属性添加到 application.properties 文件中: spring.datasource.url=jdbc:h2:mem:mydb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= 现在,假设有一个名为 person 的表。在此,使用一个基本的 SQL 脚本为数据库添加数据。默认情况下,Spring Boot 会加载 data.sql 文件: INSERT INTO "person" VALUES (1, 'Abderrahim', 'Azhrioun'); INSERT INTO "person" VALUES (2, 'David', 'Smith'); INSERT INTO "person" VALUES (3, 'Jean', 'Anderson'); 2.2、对象关系映射 接下来,使用 JPA 注解将表 person 映射到一个实体。