1、概览 有时,我们会通过异步的方式来提高应用的性能和响应能力。但是也需要考虑到偶尔故障的情况,如网络问题。此时,我们可以通过重试机制来重新调用。
本文将带你了解 Spring 对异步(async)和重试(retry)操作的支持以及如何在 Spring 应用中实现带有自动重试功能的异步执行。
2、Spring Boot 示例应用 构建一个简单的微服务,调用下游服务来处理一些数据。
2.1、Maven 依赖 添加 spring-boot-starter-web 依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 2.2、实现 Spring Service 实现 EventService 类,在 processEvents 方法中调用另一个服务的方法:
public String processEvents(List<String> events) { downstreamService.publishEvents(events); return "Completed"; } 定义 DownstreamService 接口:
public interface DownstreamService { boolean publishEvents(List<String> events); } 3、实现带重试功能的异步执行 使用 spring-retry 来实现带有重试功能的异步执行。
3.1、添加 Retry 依赖 在 pom.xm 中添加 spring-retry 依赖:
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> <version>2.0.4</version> </dependency> 3.2、@EnableAsync 和 @EnableRetry 配置 添加 @EnableAsync 和 @EnableRetry 注解:
1、概览 Spring Batch 是一个强大的批处理框架,可用于开发健壮的批处理应用。
上一篇教程 介绍了 Spring Batch,本文将在此基础上带你了解如何使用 Spring Boot 设置和创建一个基本的批处理驱动应用。
2、Maven 依赖 首先,在 pom.xml 中添加 spring-boot-starter-batch 和 h2 依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-batch</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>2.1.214</version> <scope>runtime</scope> </dependency> 3、定义简单的 Spring Batch Job 创建一个 Job,从 CSV 文件导入 coffee 清单,使用自定义 Processor 对其进行转换,并将最终结果存储到内存数据库中。
3.1、开始 首先,程序入口:
@SpringBootApplication public class SpringBootBatchProcessingApplication { public static void main(String[] args) { SpringApplication.run(SpringBootBatchProcessingApplication.class, args); } } 可以看到,这是一个标准的 Spring Boot 应用。为了简单,一切配置都是使用默认值。
在 src/main/resources/application.properties 文件中定义如下属性:
file.input=coffee-list.csv 该属性包含输入 coffee 列表的位置。每一行都包含 coffee 的品牌、产地和一些特征:
1、概览 本文将带你深入了解 Spring Batch。它是一个批处理框架,专为执行批处理作业而设计。
当前的 5.0.0 版本支持 Spring 6 和 Java 17。
2、工作流基础 Spring Batch 遵循传统的批处理架构,其中 Job Repository 负责 Job 的调度和交互。
一项工作(Job)可以有多个步骤(Step)。每个步骤通常都遵循 读取数据、处理数据 和 写入数据 的顺序。
当然,框架会在这里完成大部分繁重的工作,尤其是在处理 Job 的底层持久化时 - 本文使用 h2 作为 Job Repository。
2.1、应用示例 在本例中,我们需要将一些财务交易数据从 CSV 迁移到 XML。
输入文件的结构非常简单。
每行包含一笔交易,由用户名(username)、用户 ID(userid)、交易日期(transaction_date)和金额(transaction_amount)组成:
username, userid, transaction_date, transaction_amount devendra, 1234, 31/10/2015, 10000 john, 2134, 3/12/2015, 12321 robin, 2134, 2/02/2015, 23411 3、Maven 依赖 本项目需要依赖 Spring Core、Spring Batch 和 H2 数据库:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>6.
在 Spring Boot 应用中,默认使用 Logback 来记录日志。可以在 application.yaml 或者是 logback-spring.xml 中配置 Logger 的日志级别。
有以下几个常见的日志级别(从低到高):
TRACE(跟踪):最低级别的日志,用于输出详细的调试信息,通常用于追踪代码的执行路径。 DEBUG(调试):用于输出调试信息,帮助开发人员调试应用程序。 INFO(信息):用于输出一般性的信息,例如应用程序的启动信息、重要事件等。 WARN(警告):用于输出警告信息,表示潜在的问题或不符合预期的情况,但不会影响应用程序的正常运行。 ERROR(错误):最高级别的日志,用于输出错误信息,表示发生了一个错误或异常情况,可能会影响应用程序的正常运行。 级别越低,包含的信息越详细,级别越高,包含的信息越严重和重要。当设置日志级别时,只有达到或高于该级别的日志才会被记录和输出,而低于该级别的日志将被忽略。如:如果将日志级别设置为 INFO,则会记录和输出 INFO、WARN 和 ERROR 级别的日志,而 DEBUG 和 TRACE 级别的日志将被忽略。这有助于控制日志的详细程度和输出量,以适应特定的调试或生产环境要求。
Log4j 建议只使用 ERROR、WARN、INFO、DEBUG 四个级别。
以 ROOT Logger 的配置为例 在 application.yaml 中配置 logging: level: ROOT: DEBUG 在 logback-spring.xml 中配置 首先,需要在 application.yaml 中配置 logback-spring.xml 配置文件的位置:
logging: config: classpath:logback-spring.xml 然后,在 logback-spring.xml 中配置 ROOT Logger 的日志级别:
<configuration> <!-- 继承 Spring 预定义的 Logback 配置 --> <include resource="org/springframework/boot/logging/logback/base.xml"/> <!
1、概览 本文将带你了解如何在 Spring Boot 中实现定时地往浏览器推送 WebSockets 消息。
另一种方法是使用服务器发送事件 (SSE),但本文不涉及这一点。
Spring 提供了多种调度方式。如 @Scheduled 注解,以及 Project Reactor 提供的 Flux::interval 方法,对于 Webflux 应用来说,该方法开箱即用,它还可以作为独立库用于任何 Java 项目。
此外,还有一些更专业的三方调度框架,如 Quartz Scheduler,但这不在本文范畴。
2、简单的聊天应用 在 上一篇文章 中,使用 WebSockets 构建了一个聊天应用。现在让我们用一项新功能来扩展它:聊天机器人。聊天机器人是向浏览器推送预定消息的服务器端组件。
2.1、Maven 依赖 先在 Maven 中添加必要依赖, pom.xml 如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-core</artifactId> </dependency> <dependency> <groupId>com.github.javafaker</groupId> <artifactId>javafaker</artifactId> <version>1.0.2</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency> 2.2、JavaFaker 使用 JavaFaker 库生成机器人信息。该库通常用于生成测试数据。在这里,用于为聊天室添加一位名为 “Chuck Norris” 的访客。
代码如下:
Faker faker = new Faker(); ChuckNorris chuckNorris = faker.
1、概览 本文将带你了解如何在 Spring WebSockets 中使用 @SendToUser 注解向特定 Session 或特定用户发送消息。
有关上述 Spring WebSockets 的介绍,请参阅 上一篇文章。
2、WebSocket 配置 首先,需要配置 Message Broker 和 WebSocket 应用端点:
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic/", "/queue/"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/greeting"); } } 通过 @EnableWebSocketMessageBroker 注解,启用了在 WebSocket 上使用 STOMP(Streaming Text Oriented Messaging Protocol)的基于 Broker 的消息传递。需要强调的是,这个注解需要与 @Configuration 一起使用。
继承 AbstractWebSocketMessageBrokerConfigurer 并不是必须的,但这可以更容易地自定义导入的配置。
在第一个方法中,建立了一个简单的基于内存的 Message Broker,通过以 /topic 和 /queue 为前缀的目标将消息传回客户端。
1、概览 本文将带你学习如何使用 Spring 4 中引入的 WebSocket 功能来实现一个简单的聊天应用。
WebSockets 是 Web 浏览器和服务器之间的一种双向、全双工、持久连接。一旦建立了 WebSocket 连接,该连接就会一直打开,直到客户端或服务器关闭该连接。
2、Maven 依赖 在 pom.xml 中添加所需的依赖:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>5.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>5.2.2.RELEASE</version> </dependency> 此外,还需要添加 Jackson 依赖,用于序列化/反序列化 JSON 格式的消息。
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.10.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.2</version> </dependency> 3、启用 WebSocket 首先,在配置类上通过 @EnableWebSocketMessageBroker 注解来启用 WebSocket 功能。
配置类需要继承 AbstractWebSocketMessageBrokerConfigurer。
顾名思义,它能在 Message Broker 的支持下处理 WebSocket 消息:
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.
1、概览 在 Spring Boot 应用中,一般使用 RestTemplate 来执行同步 HTTP 请求。数据通常以 JSON 的形式返回,而 RestTemplate 可以进行自动转换。
本文将带你了解,如何在 RestTemplate 中把响应的 JSON 数组转换为 Object 数组、POJO 数组和 POJO 集合。
2. JSON、POJO 和 Service 假设我们有一个端点 http://localhost:8080/users,它返回如下 JSON 格式的用户列表:
[{ "id": 1, "name": "user1", }, { "id": 2, "name": "user2" }] 对应的 User 类如下:
public class User { private int id; private String name; // get/set 方法省略 } 定义 Service 接口实现 UserConsumerServiceImpl,并注入 RestTemplate:
public class UserConsumerServiceImpl implements UserConsumerService { private final RestTemplate restTemplate; public UserConsumerServiceImpl(RestTemplate restTemplate) { this.
1、背景 有好几次线上发布老应用时,遭遇代码启动报错,具体错误如下:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'xxxManageFacadeImpl': Bean with name 'xxxManageFacadeImpl' has been injected into other beans [xxxProductMaintenceFacadeImpl] in its raw version as part of a circular reference, but has eventually been wrap means thff, for expped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesallowEageOfType' with the 'allowEagerInit' flag turned off, for example 咋眼一看,这不就是 Spring Bean 循环依赖报错吗?脑海立马闪过那些年为了进阿里面试时被死亡 N 连问的场景,那时我们都知道 Spring 已经支持 Bean 循环依赖,为啥我们的 Spring Boot 应用启动时还报这个错误?于是,带着这个问题重新温习下 Spring 如何解决 Bean 循环依赖。
1、概览 Spring Boot 默认使用 Jackson ObjectMapper 实例来序列化和反序列化 JSON 格式的响应与请求。
本文将带你了解如何在 Spring Boot 中自定义 Jackson ObjectMapper 选项,以及配置序列化和反序列化选项的最常用方法。
2、默认配置 默认情况下,Spring Boot 禁用了以下功能:
MapperFeature.DEFAULT_VIEW_INCLUSION DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES SerializationFeature.WRITE_DATES_AS_TIMESTAMPS 从一个简单的例子开始:
客户端向 /coffee?name=Lavazza 端点发送 GET 请求。 Controller 返回一个新的 Coffee 对象。 Spring 使用 ObjectMapper 将 POJO 序列化为 JSON。 使用 String 和 LocalDateTime 对象来演示自定义选项:
public class Coffee { private String name; private String brand; private LocalDateTime date; // get / set 省略 } 定义一个简单的 REST Controller 来演示序列化:
@GetMapping("/coffee") public Coffee getCoffee( @RequestParam(required = false) String brand, @RequestParam(required = false) String name) { return new Coffee() .