Spring Boot v3.3.4 现已发布。
🐞 Bug 修复 当封装了 AbstractRoutingDataSource 时,management.health.db.ignore-routing-datasources=true 无效 #42322 OAuth2ClientProperties 验证错误信息中缺少详细信息 #42279 来自未使用的错误配置 SSL bundle 的 FileNotFoundException #42169 当 spring-web 不在 classpath 上时,ZipkinHttpClientSender 会出现 “Failed to introspect Class”(类自省失败)#42161 与容器 Bean 一起使用时,@RestartScope 可能会导致 “Recursive update(递归更新)”异常 #42107 JarLauncher 无法加载大型 jar 文件 #42079 PropertiesMigrationListener 错误地将具有 group 的属性报告为已废弃属性 #42071 在 MongoDB 中使用空字符串的 ‘replica-set-name’ 属性将导致 ClusterType=REPLICA_SET #42059 默认 Logback 配置使用过时的 “converterClass” 属性 #42006 📔 文档 关于 spring.jmx.enabled 不适用于第三方库的文件 #42285 更新指向 Log4j2 系统属性(system properties)的链接 #42263 参考指南中的 GraphQL 链接重定向到根目录,而不是特定部分 #42208 参考指南中 “被动接收信息部分(Receive a message reactively section)” 的语法错误 #42200 autotime 启用、percentiles 和 percentiles-historgram 属性被废弃的原因令人困惑。 #42193 在属性文件中用 RFC 9457 取代 RFC 7807 #42190 不支持将配置属性绑定到带有默认值的 Kotlin 值类的文档 #42176 更新文档以反映新的未找到 Handler 的异常行为 #42167 波兰语配置属性参考 #42165 移除指向 “将 Spring Boot JAR 应用转换为 WAR” 的链接,因为该指南已不再可用 #42111 修正 Metric 文档页面上的 StatsD 链接错字 #42109 改进无需构建包的 docker 文档 #42106 改进 “命令行自动补全”中的文档 #42103 测试部分缺少 Kotlin 代码示例 #42094 修复 Colima 的 Docker 配置中的错误命令 #42078 Gradle Plugin AOT 文档中有示例错误 #42046 🔨 依赖升级 升级依赖到 Groovy 4.
1、简介 在处理分布式系统时,调用外部服务并保持低延迟是一项至关重要的任务。
本文将带你了解如何使用 OpenFeign 和 CompletableFuture 来并行处理多个 HTTP 请求,处理错误,并设置网络和线程超时。
2、示例项目 为了说明并行请求的用法,我们要实现一个功能,允许客户在网站上购买物品。首先,该服务发出一个请求,根据客户所在国家获取可用的付款方式。其次,它发送一个请求给客户生成有关购买的报告。购买报告不包括有关付款方式的信息。
先添加 spring-cloud-starter-openfeign 依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> 3、创建调用外部依赖的客户端 使用 @FeignClient 注解创建两个指向 localhost:8083 的客户端:
@FeignClient(name = "paymentMethodClient", url = "http://localhost:8083") public interface PaymentMethodClient { @RequestMapping(method = RequestMethod.GET, value = "/payment_methods") String getAvailablePaymentMethods(@RequestParam(name = "site_id") String siteId); } 第一个客户端名为 paymentMethodClient。它调用 GET /payment_methods,使用代表客户所在国家/地区的 site_id 请求参数获取可用的付款方式。
第二个客户端如下:
@FeignClient(name = "reportClient", url = "http://localhost:8083") public interface ReportClient { @RequestMapping(method = RequestMethod.POST, value = "/reports") void sendReport(@RequestBody String reportRequest); } 我们将其命名为 reportClient,它调用 POST /reports 生成购买报告。
1、概览 本文将带你了解如何在 Spring Boot 应用中使用 HttpStatusCode,重点是 3.3.3 版中引入的最新增强功能。通过这些增强功能,HttpStatusCode 已被纳入 HttpStatus 实现,从而简化了我们处理 HTTP 状态码的方式。
这些改进的主要目的是提供一种更灵活、更可靠的方法来处理标准和自定义 HTTP 状态码,使我们在处理 HTTP 响应时具有更高的灵活性和可扩展性,同时保持向后兼容性。
2、HttpStatus 枚举 在 Spring 3.3.3 之前,HTTP 状态码在 HttpStatus 中表示为枚举。这限制了自定义或非标准 HTTP 状态码的使用,因为枚举是一组固定的预定义值。
尽管 HttpStatus 类尚未被弃用,但一些返回原始 Integer 状态码的枚举和方法(如 getRawStatusCode() 和 rawStatusCode())现已被弃用。
使用 @ResponseStatus 注解来提高代码的可读性仍然是我们推荐的方法。
我们可以将 HttpStatus 与 HttpStatusCode 结合使用,以实现更灵活的 HTTP 响应管理:
@GetMapping("/exception") public ResponseEntity<String> resourceNotFound() { HttpStatus statusCode = HttpStatus.NOT_FOUND; if (statusCode.is4xxClientError()) { return new ResponseEntity<>("Resource not found", HttpStatusCode.valueOf(404)); } return new ResponseEntity<>("Resource found", HttpStatusCode.
1、概览 动态管理应用程序配置是许多实际应用场景中的关键要求。在微服务架构中,由于扩展操作或负载条件的变化,不同的服务可能需要即时更改配置。在其他情况下,应用程序可能需要根据用户偏好、来自外部 API 的数据调整其行为,或满足动态变化的要求。
application.properties 文件是静态的,在不重启应用的情况下无法更改。不过,Spring Boot 提供了几种强大的方法,可在运行时调整配置而无需停机。无论是在实时应用程序中切换功能、更新数据库连接以实现负载均衡,还是在不重新部署应用的情况下更改第三方集成的 API Key,Spring Boot 的动态配置功能都能为这些复杂的环境提供所需的灵活性。
本文将带你了解几种无需直接修改 application.properties 文件即可动态更新 Spring Boot 应用程序中属性的策略。这些方法可满足不同的需求,从非持久性内存更新到使用外部文件进行持久性更改。
本文中的示例使用 Spring Boot 3.2.4、JDK17 以及 Spring Cloud 4.1.3。不同版本的 Spring Boot 可能需要对代码进行轻微调整。
2、使用 Prototype Scope Bean 当我们需要动态调整特定 Bean 的属性,而不影响已创建的 Bean 实例或更改全局应用程序状态时,一个简单的使用 @Value 直接注入的 @Service 类是不够的,因为这些属性在 Application Context 的生命周期内是静态的。
相反,可以使用 @Configuration 类中的 @Bean 方法创建具有可修改属性的 Bean。这种方法允许在应用程序执行过程中动态更改属性:
@Configuration public class CustomConfig { @Bean @Scope("prototype") // Scope 为 prototype public MyService myService(@Value("${custom.property:default}") String property) { return new MyService(property); } } 通过使用 @Scope("prototype") 注解,我们可以确保每次调用 myService(.
日志记录是应用故障排除的重要组成部分,也是可观测性的三大支柱之一,另外两个是指标和追踪(Trace)。没有人喜欢在生产环境中瞎操作,当事故发生时,开发者会很乐意看到日志文件。日志通常以人类可读的格式输出。
结构化日志是一种技术,其中日志输出以定义良好的格式编写,通常是机器可读的。这种格式可以输入到日志管理系统中,从而实现强大的搜索和分析功能。结构化日志最常用的格式之一是 JSON。
Spring Boot 3.4 开箱即支持结构化日志。它支持 Elastic Common Schema(ECS)和 Logstash 格式,也可以使用自己的格式进行扩展。
结构化日志的 Hello World 在 start.springboot.io 上创建一个新项目,不需要添加任何依赖,但至少要选择 Spring Boot 3.4.0-M2。
要在控制台上启用结构化日志记录,请将如下配置添加到 application.properties 中:
logging.structured.format.console=ecs 这将指示 Spring Boot 以 Elastic Common Schema(ECS) 格式输出日志。
启动应用,你就会看到日志是 JSON 格式的:
{"@timestamp":"2024-07-30T08:41:10.561295200Z","log.level":"INFO","process.pid":67455,"process.thread.name":"main","service.name":"structured-logging-demo","log.logger":"com.example.structured_logging_demo.StructuredLoggingDemoApplication","message":"Started StructuredLoggingDemoApplication in 0.329 seconds (process running for 0.486)","ecs.version":"8.11"} 将结构化日志记录到文件 你还可以将结构化日志写入文件。例如,这可以用于在控制台上打印人类可读的日志,同时将结构化日志写入文件以供机器读取。
要启用此功能,请将如下配置添加到 application.properties 中,并确保删除 logging.structured.format.console=ecs 设置:
logging.structured.format.file=ecs logging.file.name=log.json 现在启动应用,你会看到控制台上有人类可读的日志,而 log.json 文件则包含机器可读的 JSON 内容。
添加额外字段 结构化日志的一个强大功能是,开发人员可以以结构化的方式在日志事件中添加信息。例如,你可以在每个日志事件中添加用户 ID,然后根据该 ID 进行过滤,查看这个特定用户做了什么。
Elastic Common Schema 和 Logstash 都在 JSON 中包含了 Mapped Diagnostic Context 的内容。
Spring Boot v3.3.3 发布了。
⭐ 新特性 在 JavaVersion 枚举中添加 TWENTY_THREE #41716 🐞 Bug 修复 继承 DefaultErrorAttributes 并覆写 getErrorAttributes() 会被调用两次 #41995 在使用 WebFlux 时,当 ResponseStatusException 的原因是 BindingResult 异常时,server.error.include-binding-errors=ALWAYS 不生效 #41987 将 BOOT-INF/lib 中的 jar 添加到 classpath 时,PropertiesLauncher 不遵循 classpath.idx #41970 /cloudfoundryapplication 下 SBOM 端点的 Web 扩展不可用 #41890 启动器(Launcher)的 ClassLoader 不再具有并行功能 #41873 spring-boot-testcontainers 会在 AOT 处理过程中导致不必要的容器初始化 #41859 当 Reactor 不在类路径上时,ReactiveElasticsearchRepositoriesAutoConfiguration 应关闭 #41678 当 classifier 设置为非默认值时,mvn spring-boot:build-image 失败 #41661 Spring Boot Maven 插件 AOT 无法使用 module-info.
1、概览 无论是用户注册、密码重置还是促销活动,发送电子邮件都是现代 Web 应用的一项重要功能。
本文将带你了解如何在 Spring Boot 应用中使用 SendGrid 发送电子邮件。
2、SendGrid 设置 在开始之前,我们首先需要一个 SendGrid 账户。SendGrid 提供了免费套餐,允许我们每天发送多达 100 封电子邮件,这对于演示来说已经足够了。
注册完成后,需要创建一个 API Key 来对我们发送到 SendGrid 服务的请求进行 身份认证。
3、项目设置 在开始使用 SendGrid 发送电子邮件之前,需要添加 SDK 依赖并配置应用。
3.1、依赖 首先,在项目的 pom.xml 文件中添加 SendGrid SDK 依赖:
<dependency> <groupId>com.sendgrid</groupId> <artifactId>sendgrid-java</artifactId> <version>4.10.2</version> </dependency> 该依赖为我们提供了与 SendGrid 服务交互和从应用发送电子邮件所需的类。
3.2、定义 SendGrid 配置属性 现在,为了与 SendGrid 服务交互并向用户发送电子邮件,我们需要配置 API Key 以验证 API 请求。我们还需要配置发件人姓名和电子邮件地址,它们应与我们在 SendGrid 账户中设置的发件人身份相匹配。
我们在项目的 application.yaml 文件中配置这些属性,并使用 @ConfigurationProperties 将这些值映射到 POJO,Service 层在与 SendGrid 交互时会引用配置的 POJO:
@Validated @ConfigurationProperties(prefix = "com.
1、简介 本文将带你了解如何在 Spring Boot 应用中使用 ProblemDetail 响应错误信息,无论我们处理的是 REST API 还是 Reactive Stream(响应式流),它都提供了一种向客户端传达错误的标准化方式。
2、为什么要关注 ProblemDetail? 使用 ProblemDetail 来标准化错误响应对任何 API 都至关重要。
它可以帮助客户理解和处理错误,提高 API 的可用性和可调试性。这将带来更好的开发体验和更强大的应用。
采用它还有助于提供更翔实的错误信息,这对维护我们的服务和排除故障至关重要。
3、传统的错误处理方式 在 ProblemDetail 之前,我们经常在 Spring Boot 中实现自定义 ExceptionHandler 和 ResponseEntity 来处理错误。我们会创建自定义的错误响应结构。这导致了不同 API 之间的不一致性。
这种方式不仅需要大量的模板代码。而且,缺乏表示错误的标准化方式,因此客户端很难统一解析和理解错误信息。
4、ProblemDetail 规范 ProblemDetail 规范是 RFC 7807 标准的一部分。它为错误响应定义了一致的结构,包括诸如类型(type)、标题(title)、状态(status)、详情(detail)和实例(instance)等字段。这种标准化提供了一个通用的错误信息格式,有助于 API 开发人员和使用者。
实现 ProblemDetail 可确保我们的错误响应具有可预测性并易于理解。这反过来提高了我们的 API 和其客户端之间的整体沟通效果。
5、在 Spring Boot 中实现 ProblemDetail 在 Spring Boot 中有多种方法可以实现 ProblemDetail。
5.1、通过配置属性启用 ProblemDetail 我们可以添加一个配置属性来启用它。对于 RESTful 服务,在 application.properties 中添加以下属性:
spring.mvc.problemdetails.enabled=true 此属性可使 ProblemDetail 自动用于基于 MVC(servlet 栈)的应用中的错误处理。
1、概览 本文将带你了解 Spring Boot @MockBeans 注解的用法。
2、示例项目 以一个简单的票据验证器(Ticket Validator)示例为例:
public class TicketValidator { private CustomerRepository customerRepository; private TicketRepository ticketRepository; public boolean validate(Long customerId, String code) { customerRepository.findById(customerId) .orElseThrow(() -> new RuntimeException("Customer not found")); ticketRepository.findByCode(code) .orElseThrow(() -> new RuntimeException("Ticket with given code not found")); return true; } } 如上,我们定义了 validate() 方法,用于检查数据库中是否存在给定数据。它依赖 CustomerRepository 和 TicketRepository。
现在,来看看如何使用 Spring 的 @MockBean 和 @MockBeans 注解创建测试和模拟依赖。
3、@MockBean 注解 Spring 框架提供了 @MockBean 注解,用于模拟依赖以进行测试。该注解允许我们定义特定 Bean 的模拟版本。新创建的模拟 Bean 将被添加到 Spring ApplicationContext 中。因此,如果已经存在相同类型的 Bean,它将被替换为模拟版本。
Spring Boot 中的 application.yaml / application.properties 配置文件用于定义应用运行时需要的配置属性。
Spring Boot 提供了强大的配置属性绑定功能,可以把配置文件中的属性绑定到 Java Bean,并且会根据 Java Bean 的字段类型对配置属性进行必要的转换。
绑定属性到 Bean 通过一个简单的示例来看看如何把配置文件中的配置属性绑定到 Bean,并且自动转换其类型。
本文使用的 Spring Boot 版本是 3.3.1。
创建 Spring Boot 项目 创建任意 Spring Boot 应用。
定义配置属性 在 src/main/resources 目录下创建 application.yaml 配置文件,并在其中定义如下自定义的配置属性:
app: # 数值 port: 8080 # 字符串 title: "Spring Boot 属性绑定测试" # Duration duration: 15s # DataSize data-size: 10MB # 集合 file-types: ["png", "jpeg"] 如上,在配置文件中定义了几个不同类型的配置属性。在本例中,这些配置属性的名称没有任何意义,随意取的。
定义配置 Bean 在 cn.springdoc.demo.prop 包下定义与配置文件中属性相对应的 Bean。
package cn.