Spring

Spring Websockets 的 @SendToUser 注解

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 为前缀的目标将消息传回客户端。

Spring WebSocket 简介

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.

Spring RestTemplate 解析 JSON 数组

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.

Spring Bean 循环依赖

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 循环依赖。

JdbcClient 返回自增 ID

JdbcClient 是 Spring 6.1 引入的一个 Jdbc 客户端工具类,提供了 Fluent 链式调用风格的查询和更新方法,支持 JDBC 风格的位置参数和 Spring 风格的命名参数绑定。 本文将带你了解,如何在使用 JdbcClient 执行 insert 操作时返回自增 ID。 关于 JdbcClient 更多详细的用法可以参阅 “Spring 6 JdbcClient API 指南” 和 “Spring Boot 中的新 JDBC 客户端: JdbcClient” 创建数据表 在本地 MYSQL 数据库 demo 中创建一张简单的 t_user 表,如下: CREATE TABLE `t_user` ( `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `enabled` tinyint unsigned NOT NULL COMMENT '是否启用。0:禁用,1:启用', `name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '名字', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户'; 其中, id 列是自增列。

给 Spring REST API 设置请求超时

1、概览 本文将带你了解给 Spring REST API 设置请求超时的几种方法。 当资源耗时过长时,请求超时机制可以避免糟糕的用户体验。当然也可以使用断路器模式(Circuit Breaker pattern)来实现,本文不细说。 2、@Transactional 超时 在数据库调用中实现请求超时的一种方法是利用 Spring 的 @Transactional 注解。它有一个 timeout 属性可以设置。该属性的默认值是 -1,相当于没有任何超时。 例如,假设将超时设置为 30 秒。如果注解方法的执行时间超过这个秒数,就会抛出异常。这对于回滚长时间运行的数据库查询可能很有用。 编写一个非常简单的 JPA Repository,它代表一个外部服务,该服务需要太长时间才能完成并导致超时。 这个 Repository 中有一个耗时的方法: public interface BookRepository extends JpaRepository<Book, String> { default int wasteTime() { Stopwatch watch = Stopwatch.createStarted(); // 延迟 2 秒 while (watch.elapsed(SECONDS) < 2) { int i = Integer.MIN_VALUE; while (i < Integer.MAX_VALUE) { i++; } } } } 如果在超时时间为 1 秒的事务中调用 wasteTime() 方法,超时时间将在方法执行完毕之前结束:

在 Spring AOP 中获取 Advise 方法信息

1、简介 本文将带你了解如何使用 Spring AOP Aspect 获取 Advise 方法的签名、参数、注解以及其他的额外信息。 2、Maven 依赖 首先,在 pom.xml 中添加 spring-boot-starter-aop Starter 依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> 3、创建 Pointcut 注解 创建一个 AccountOperation 注解,作为切面中的切点: @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AccountOperation { String operation(); } 注意,切点(Pointcut)不一定非要使用注解定义。也可以使用 Spring AOP 提供的 Pointcut 定义语言定义其他 Pointcut 类型,如类中的某些方法、以某些前缀开头的方法等。 4、创建示例 Service 4.1、Account 类 创建一个 Account POJO,带有 accountNumber 和 balance 属性。 在 service 方法中使用它作为方法参数: public class Account { private String accountNumber; private double balance; // get/set toString方法省略 } 4.

使用 WebClient 获取 JSON 对象集合

1、概览 从 Spring 5 开始,可以使用 WebClient 以响应式、非阻塞的方式执行服务之间的 REST 通信。WebClient 是新的 WebFlux 框架的一部分,构建于 Project Reactor 之上。它使用 Fluent 风格的响应式 API,底层实现使用 HTTP 协议。 当发起 Web 请求时,数据通常会以 JSON 格式返回,本文将带你了解如何使用 WebClient 将响应的 JSON 数组转换为 Java Object 数组、POJO 数组和 POJO 集合。 2、依赖 在 pom.xml 中添加如下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.projectreactor</groupId> <artifactId>reactor-spring</artifactId> <version>1.0.1.RELEASE</version> </dependency> 3、JSON、POJO 和 Service 从端点 http://localhost:8080/readers 开始,它以 JSON 数组的形式返回读者最喜欢的书籍列表: [{ "id": 1, "name": "reader1", "favouriteBook": { "author": "Milan Kundera", "title": "The Unbearable Lightness of Being" } }, { "id": 2, "name": "reader2" "favouriteBook": { "author": "Douglas Adams", "title": "The Hitchhiker's Guide to the Galaxy" } }] 还需要相应的 Reader 和 Book 类来处理数据:

Spring RestTemplate 异常:“Not enough variables available to expand”

1、概览 本文将带你了解 Spring RestTemplate 抛出 IllegalArgumentException: Not enough variables available to expand 异常的原因以及解决办法。 2、原因 简而言之,当试图在 GET 请求参数中发送 JSON 数据时,通常会导致这个异常。 RestTemplate 提供了 getForObject 方法,通过在指定的 URL 上发出 GET 请求来获取表示对象。 出现异常的主要原因是 RestTemplate 将大括号中封装的 JSON 数据视为 URI 变量的占位符。 由于没有为预期的 URI 变量提供任何值,getForObject 方法就会抛出异常。 例如,尝试发送 {"name": "HP EliteBook"} 作为查询参数: String url = "http://products.api.com/get?key=a123456789z&criterion={\"name\":\"HP EliteBook\"}"; Product product = restTemplate.getForObject(url, Product.class); 将导致 RestTemplate 抛出异常: java.lang.IllegalArgumentException: Not enough variable values available to expand 'name' 3、示例应用 创建一个只有一个 GET 端点的基本 REST API 示例,来复现 RestTemplate 抛出 IllegalArgumentException 异常的情况。

Spring 中的 @Component 注解

1、概览 本文将带你全面了解 Spring @Component 注解及相关领域。 2、Spring ApplicationContext 在了解 @Component 之前,首先需要了解一下 Spring ApplicationContext。 Spring ApplicationContext 是 Spring 保存对象实例的地方,Spring 已确定这些实例将被自动管理和分发。这些实例被称为 Bean。 Spring 的一些主要功能包括 Bean 管理和依赖注入。 利用控制反转(Inversion of Control),Spring 可以从应用中收集 Bean 实例,并在适当的时候使用它们。可以在 Spring 中定义 Bean 依赖,而无需处理这些对象的设置和实例化。 使用 @Autowired 等注解将 Spring 管理的 Bean 注入应用的能力是在 Spring 中创建功能强大且可扩展代码的驱动力。 那么,如何让 Spring 来管理的 Bean 呢?可以利用 Spring 的自动 Bean 检测功能,通过在类中使用元注解(Stereotype Annotation)来实现。 3、@Component @Component 是一个注解,它允许 Spring 自动检测自定义 Bean。 换句话说,无需编写任何明确的代码,Spring 就能做到: 扫描应用,查找注解为 @Component 的类 将它们实例化,并注入任何指定的依赖 在需要的地方注入 不过,大多数时候应该使用更专业的元(Stereotype)注解来实现这一功能。 3.1、Spring 元注解 Spring 提供了一些专门的元注解:@Controller、@Service 和 @Repository。它们都提供了与 @Component 相同的功能。