当前位置: 首页 > news >正文

Spring Boot+Redis 实现消息队列实践示例

Spring Boot+Redis 实现一个轻量级的消息队列

文章目录

  • Spring Boot+Redis 实现一个轻量级的消息队列
  • 0.前言
  • 1.基础介绍
  • 2.步骤
    • 2.1. 引入依赖
    • 2.2. 配置文件
    • 2.3. 核心源码
  • 4.总结
    • 答疑
  • 5.参考文档
  • 6. Redis从入门到精通系列文章

在这里插入图片描述

0.前言

本文将介绍如何利用Spring Boot与Redis结合实现消息队列的实践示例。消息队列是一种常用的解耦和异步通信的机制,可以在系统中实现高效的消息传递和处理。而Redis作为一种高性能的内存数据库,具备发布/订阅功能,非常适合用于构建消息队列系统。

在本实践示例中,我们将使用Spring Boot框架和Redis作为基础,通过Redis的发布/订阅模型来实现简单的消息队列。 如何通过消息通道进行消息的发布和订阅。

在开始之前,你需要对Spring Boot和Redis有一定的了解,并确保已正确配置好开发环境。本文将提供实际的代码示例和详细的步骤说明, 并能够根据具体业务需求进行扩展和定制。

1.基础介绍

Redis提供了发布/订阅(Publish/Subscribe)模式,用于实现消息的广播和异步通信。下面是关于Redis发布/订阅模式的介绍:

发布/订阅模式(Pub/Sub)
发布/订阅模式是一种消息通信模式,其中消息的发布者(Publisher)将消息发送到特定的频道(Channel),而订阅者(Subscriber)可以订阅一个或多个频道以接收消息。这种模式允许消息的广播和异步传递,发送者和接收者之间解耦。

Redis的发布/订阅功能
Redis提供了原生的发布/订阅功能,使得开发者可以使用Redis作为消息中间件来实现高效的消息传递。以下是与Redis发布/订阅相关的关键概念和操作:
下面是将Redis发布/订阅功能整理成表格的示例:

概念说明
频道(Channel)Redis中用于发布和订阅消息的通道。每个消息都被发布到一个特定的频道,而订阅者可以选择订阅一个或多个感兴趣的频道。
发布消息(Publish)通过使用PUBLISH命令,发布者可以将消息发送到指定的频道。一旦消息被发布到频道,所有订阅该频道的客户端将接收到该消息。
订阅频道(Subscribe)通过使用SUBSCRIBE命令,客户端可以订阅一个或多个频道。一旦订阅成功,客户端将成为该频道的订阅者,可以接收到该频道上发布的消息。
取消订阅频道(Unsubscribe)通过使用UNSUBSCRIBE命令,客户端可以取消对一个或多个频道的订阅。当客户端不再对某个频道感兴趣时,可以选择取消订阅。
模式匹配订阅(Pattern Subscription)Redis支持使用PSUBSCRIBE命令进行模式匹配订阅。通过指定一个模式,可以订阅与该模式匹配的多个频道。

通过Redis的发布/订阅功能,可以构建高效的消息系统,实现消息的广播和异步传递。发布者将消息发布到特定的频道,而订阅者可以选择订阅感兴趣的频道来接收消息。这种模式的优点包括解耦、异步通信和实时性等,适用于很多场景,如实时通知、事件驱动系统和分布式系统间的消息传递等。

本文我们通过Spring Boot +Redis 实现一个轻量级的消息队列。

2.步骤

2.1. 引入依赖

<dependencies><!-- Spring Data Redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
</dependencies>

2.2. 配置文件

# Redis连接配置
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=your_password
spring.redis.database=0# Redis连接池配置
spring.redis.jedis.pool.max-active=50
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=5
spring.redis.jedis.pool.max-wait=-1

在上面的配置中,您可以根据实际情况修改以下属性:

  • spring.redis.host:Redis服务器的主机名或IP地址。
  • spring.redis.port:Redis服务器的端口号。
  • spring.redis.password:Redis服务器的密码(如果有的话)。
  • spring.redis.database:Redis数据库的索引,默认为0。

另外,您还可以配置Redis连接池的属性,以控制连接池的行为。在示例配置中,设置了以下连接池属性:

  • spring.redis.jedis.pool.max-active:连接池中的最大活动连接数。
  • spring.redis.jedis.pool.max-idle:连接池中的最大空闲连接数。
  • spring.redis.jedis.pool.min-idle:连接池中的最小空闲连接数。
  • spring.redis.jedis.pool.max-wait:从连接池获取连接的最大等待时间(毫秒),-1表示无限等待。

如果 使用的是YAML格式的配置文件(application.yml),可以将上述配置转换为相应的格式:

spring:redis:host: 127.0.0.1port: 6379password: your_passworddatabase: 0redis.jedis.pool:max-active: 50max-idle: 10min-idle: 5max-wait: -1

请根据您的实际Redis服务器配置进行调整,并根据需要添加其他相关配置,如超时设置、SSL配置等。

2.3. 核心源码

当使用Spring Boot与Redis结合实现消息队列时,可以使用Redis的发布/订阅功能来处理消息的发布和订阅。下面是

接下来,创建一个消息发布者和一个消息订阅者的类。在发布者类中,使用RedisTemplate来发布消息,而在订阅者类中,通过实现MessageListener接口来处理接收到的消息。

// 消息发布者
@Component
public class MessagePublisher {private final RedisTemplate<String, String> redisTemplate;private final ChannelTopic topic;public MessagePublisher(RedisTemplate<String, String> redisTemplate, ChannelTopic topic) {this.redisTemplate = redisTemplate;this.topic = topic;}public void publishMessage(String message) {redisTemplate.convertAndSend(topic.getTopic(), message);}
}

消息订阅者

// 消息订阅者
@Component
public class MessageSubscriber implements MessageListener {@Overridepublic void onMessage(Message message, byte[] pattern) {String receivedMessage = message.toString();// 处理接收到的消息System.out.println("Received message: " + receivedMessage);}
}

接下来,配置Redis消息监听容器,以便启动消息监听器:

@Configuration
public class RedisConfig {@Beanpublic ChannelTopic topic() {return new ChannelTopic("messageQueue"); // 定义消息队列的通道名称}@Beanpublic MessageListenerAdapter messageListenerAdapter(MessageSubscriber messageSubscriber) {return new MessageListenerAdapter(messageSubscriber);}@Beanpublic RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory,MessageListenerAdapter messageListenerAdapter,ChannelTopic topic) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(redisConnectionFactory);container.addMessageListener(messageListenerAdapter, topic);return container;}
}

最后,在需要发布消息的地方,注入MessagePublisher并调用publishMessage()方法来发布消息:

@Service
public class MyService {private final MessagePublisher messagePublisher;public MyService(MessagePublisher messagePublisher) {this.messagePublisher = messagePublisher;}public void doSomethingAndPublishMessage() {// 执行一些操作String message = "Hello, Redis message queue!";messagePublisher.publishMessage(message);}
}

这样,当调用MyService中的doSomethingAndPublishMessage()方法时,消息将被发布到Redis的消息队列中,并由订阅者接收和处理。

请注意,以上示例是一个简化的实现,仅用于演示基本的消息发布和订阅流程。在实际的生产环境中,可能需要考虑更多的细节,如错误处理、消息确认机制、并发处理等。

4.总结

通过Redis的发布/订阅模型,Spring Boot利用RedisTemplate将消息发布到指定的Redis通道,同时使用MessageListenerAdapter将订阅者与消息通道绑定。当有消息发布到通道时,Redis会将消息广播给所有订阅该通道的客户端,然后MessageListenerAdapter将接收到的消息传递给相应的消息监听器进行处理。

这样,利用Redis的发布/订阅功能,我们可以实现基于Spring Boot与Redis的消息队列系统,实现消息的发布和订阅。通过这种异步的方式,消息发布者和订阅者可以解耦,提高系统的可伸缩性和性能。

答疑

上次介绍了 Redis 的pub和sub,以及Stream 有很多同学有疑惑项目中应该使用哪种。那么我们在此处再聊聊
Redis提供了两种不同的功能来实现消息队列:发布/订阅(Pub/Sub)和流(Stream)。选择使用哪种功能作为消息队列取决于您的具体需求和使用场景。

特点Redis发布/订阅(Pub/Sub)Redis流(Stream)
适用场景简单的消息广播和异步通信场景更复杂的消息队列需求,包括任务队列、事件溯源、日志收集等
消息持久化不支持消息的持久化和历史记录支持消息的持久化和历史记录
消息订阅方式订阅者选择订阅感兴趣的频道来接收消息多个消费者对消息进行消费
订阅前发布的消息无法获取先于订阅的消息可以获取订阅前发布的消息
实时性适用于需要即时通知、实时事件处理和实时数据传递的场景实时性较高,但受消费者的处理速度影响
消费者组管理不支持消费者组管理支持消费者组管理
消息顺序性消息的顺序不保证消息的顺序保证
用例示例即时聊天应用、实时通知系统、发布/订阅模式的消息传递任务队列、事件溯源、日志收集等

所以如果你的需求是简单的消息广播和异步通信,并且对消息的持久化和历史记录要求不高,可以选择使用Redis发布/订阅功能作为消息队列。而如果您需要更丰富的消息队列功能,包括消息的持久化、多个消费者的支持和消息历史记录等,那么Redis流是更好的选择。根据具体的使用场景和需求,选择适合的功能来实现消息队列。

5.参考文档

  1. Redis官方文档 - 发布/订阅:

    • 链接:https://redis.io/topics/pubsub ↗
    • 该文档提供了Redis发布/订阅功能的详细说明,包括基本概念、命令使用、示例代码和常见问题解答等。
  2. Redis命令文档 - PUBLISH:

    • 链接:https://redis.io/commands/publish ↗
    • 该文档介绍了PUBLISH命令的语法、参数和用法,以及与发布消息相关的注意事项。
  3. Redis命令文档 - SUBSCRIBE:

    • 链接:https://redis.io/commands/subscribe ↗
    • 该文档详细说明了SUBSCRIBE命令的语法、参数和用法,以及如何订阅频道并接收发布的消息。
  4. Redis命令文档 - UNSUBSCRIBE:

    • 链接:https://redis.io/commands/unsubscribe ↗
    • 该文档提供了UNSUBSCRIBE命令的说明,包括取消订阅频道的语法和参数。
  5. Redis命令文档 - PSUBSCRIBE:

    • 链接:https://redis.io/commands/psubscribe ↗
    • 该文档介绍了PSUBSCRIBE命令的用法,用于进行模式匹配订阅,可以订阅与指定模式匹配的多个频道。

6. Redis从入门到精通系列文章

  • 《Redis使用Lua脚本和Redisson来保证库存扣减中的原子性和一致性》
  • 《SpringBoot Redis 使用Lettuce和Jedis配置哨兵模式》
  • 《Redis【应用篇】之RedisTemplate基本操作》
  • 《Redis 从入门到精通【实践篇】之SpringBoot配置Redis多数据源》
  • 《Redis 从入门到精通【进阶篇】之三分钟了解Redis HyperLogLog 数据结构》
  • 《Redis 从入门到精通【进阶篇】之三分钟了解Redis地理位置数据结构GeoHash》
  • 《Redis 从入门到精通【进阶篇】之高可用哨兵机制(Redis Sentinel)详解》
  • 《Redis 从入门到精通【进阶篇】之redis主从复制详解》
  • 《Redis 从入门到精通【进阶篇】之Redis事务详解》
  • 《Redis从入门到精通【进阶篇】之对象机制详解》
  • 《Redis从入门到精通【进阶篇】之消息传递发布订阅模式详解》
  • 《Redis从入门到精通【进阶篇】之持久化 AOF详解》
  • 《Redis从入门到精通【进阶篇】之持久化RDB详解》
  • 《Redis从入门到精通【高阶篇】之底层数据结构字典(Dictionary)详解》
  • 《Redis从入门到精通【高阶篇】之底层数据结构快表QuickList详解》
  • 《Redis从入门到精通【高阶篇】之底层数据结构简单动态字符串(SDS)详解》
  • 《Redis从入门到精通【高阶篇】之底层数据结构压缩列表(ZipList)详解》
  • 《Redis从入门到精通【进阶篇】之数据类型Stream详解和使用示例》
    在这里插入图片描述大家好,我是冰点,今天的 Spring Boot+Redis 实现消息队列实践示例,全部内容就是这些。如果你有疑问或见解可以在评论区留言。

相关文章:

Spring Boot+Redis 实现消息队列实践示例

Spring BootRedis 实现一个轻量级的消息队列 文章目录 Spring BootRedis 实现一个轻量级的消息队列0.前言1.基础介绍2.步骤2.1. 引入依赖2.2. 配置文件2.3. 核心源码 4.总结答疑 5.参考文档6. Redis从入门到精通系列文章 0.前言 本文将介绍如何利用Spring Boot与Redis结合实现…...

11. 实现业务功能--获取用户信息

目录 1. 实现 Controller 2. 单体测试 3. 修复返回值存在的缺陷 3.1 用户的隐私数据&#xff1a;密码的密文和盐不能显示 3.2 将值为 null 的字段可以进行过滤 3.3 时间的格式需要进行处理&#xff0c;如 yyyy-mmmm-ddd HH:mm:ss 3.4 data 属性没有返回 4. 实现前端页…...

HTTPS

HTTPS是什么 HTTPS 属于应用层协议&#xff0c;其原理是通过SSL/TLS协议在HTTP和TCP之间插入一层安全机制。通过SSL/TLS握手过程&#xff0c;客户端和服务器协商出一个对称密钥&#xff0c;用于后续的数据加密和解密&#xff0c;从而保证数据的机密性和完整性。 为什么会需要…...

spring详解

spring是于2003年兴起的一款轻量级的&#xff0c;非侵入式的IOC和AOP的一站式的java开发框架&#xff0c;为简化企业级应用开发而生。 轻量级的&#xff1a;指的是spring核心功能的jar包不大。 非侵入式的&#xff1a;业务代码不需要继承或实现spring中任何的类或接口 IOC&…...

香港服务器备案会通过吗?

​  对于企业或个人来说&#xff0c;合规备案是网络运营的基本要求&#xff0c;也是保护自身权益的重要举措。以下内容围绕备案展开话题&#xff0c;希望为您解开疑惑。 香港服务器备案会通过吗? 目前&#xff0c;香港服务器无法备案&#xff0c;这是由于国内管理规定的限制…...

乐鑫推出 ESP ZeroCode 控制台

乐鑫科技 ESP ZeroCode 控制台是一个网页应用&#xff0c;用户只需点击鼠标&#xff0c;描述想要创建的产品类型、功能及其硬件配置&#xff0c;即可按照自身需求&#xff0c;快速生成符合 Matter 认证的固件&#xff0c;并在硬件上进行试用。试用过程中&#xff0c;如有任何不…...

从NLP到聊天机器人

一、说明 今天&#xff0c;当打电话给银行或其他公司时&#xff0c;听到电话另一端的机器人向你打招呼是很常见的&#xff1a;“你好&#xff0c;我是你的数字助理。请问你的问题。是的&#xff0c;机器人现在不仅可以说人类语言&#xff0c;还可以用人类语言与用户互动。这是由…...

相关搜索引擎常用搜索语法(Google hacking语法和FOFA语法)

一&#xff1a;Google Hack语法 Google Hacking原指利用Google搜索引擎搜索信息来进行入侵的技术和行为&#xff0c;现指利用各种搜索引擎并使用一些高级的搜索语法来搜索信息。既利用搜索引擎强大的搜索功能&#xff0c;在在浩瀚的互联网中搜索到我们需要的信息。 &#xff0…...

Mysql查询

第三章&#xff1a;select 语句 SELECT employees.employee_id,employees.department_id FROM employees WHERE employees.employee_id176; DESC departments;SELECT * FROM departments;第四章&#xff1a;运算符使用 SELECT employees.last_name,employees.salary FROM em…...

解决http下navigator.clipboard为undefined问题

开发环境下使用navigator.clipboard进行复制操作&#xff0c;打包部署到服务器上后&#xff0c;发现该功能显示为undefined&#xff1b;查相关资料后&#xff0c;发现clipboard只有在安全域名下才可以访问(https、localhost)&#xff0c;在http域名下只能得到undefined&#xf…...

mysql之host is blocked问题

程序上线一段时间之后&#xff0c;更新程序总是遇到这个问题 每次都是重启几次程序&#xff0c;或者执行 flush hosts; 毕竟指标不治本&#xff0c;抽出时间决定分析一下问题&#xff0c;查阅了几篇博客。&#xff08;感谢这几位大佬&#xff09; https://blog.51cto.com/u_…...

每日一题:2337 移动片段得到字符串

给你两个字符串 start 和 target &#xff0c;长度均为 n 。每个字符串 仅 由字符 L、R 和 _ 组成&#xff0c;其中&#xff1a; 字符 L 和 R 表示片段&#xff0c;其中片段 L 只有在其左侧直接存在一个 空位 时才能向 左 移动&#xff0c;而片段 R 只有在其右侧直接存在一个 …...

嵌入式设备的 Json 库基本使用

大家好&#xff0c;今天给介绍一款基于 C 语言的轻量级的 Json 库 – cJson。可用于资源受限的嵌入式设备中。 cJSON 是一个超轻巧&#xff0c;携带方便&#xff0c;单文件&#xff0c;简单的可以作为 ANSI-C 标准的 JSON 解析器。 cJSON 是一个开源项目&#xff0c;github 下…...

GEEMAP 中如何拉伸图像

图像拉伸是最基础的图像增强显示处理方法&#xff0c;主要用来改善图像显示的对比度&#xff0c;地物提取流程中往往首先要对图像进行拉伸处理。图像拉伸主要有三种方式&#xff1a;线性拉伸、直方图均衡化拉伸和直方图归一化拉伸。 GEE 中使用 .sldStyle() 的方法来进行图像的…...

软件测试学术顶会——ISSTA 2023 论文(网络安全方向)清单、摘要与总结

总结 本次会议涵盖的安全研究主题广泛,包括源代码分析、二进制代码分析、恶意软件检测、漏洞检测、模糊测试、程序验证等。一些热门的研究方向包括:基于机器学习的漏洞检测、大型语言模型在软件安全中的应用、区块链智能合约安全分析。这些方向都在最近几年持续发展。一些较冷门…...

基于YOLOv8模型和PCB电子线路板缺陷目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型PCB电子线路板缺陷目标检测系统可用于日常生活中检测与定位PCB线路板瑕疵&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检…...

centos安装mysql8

检查是否有mariadb rpm -qa|grep mariadb rpm -e --nodeps mariadb-server安装mysql-8.0.31-el7-x86_64.tar.gz包 安装mysql-8.0.31-el7-x86_64.tar.gz包 cd datatar -xvf mysql-8.0.31-el7-x86_64.tar.gzmv mysql-8.0.31-el7-x86_64 mysql 依赖安装 报错解决&#xff0c;安…...

【Apollo】阿波罗自动驾驶技术:引领汽车行业革新

前言 Apollo (阿波罗)是一个开放的、完整的、安全的平台&#xff0c;将帮助汽车行业及自动驾驶领域的合作伙伴结合车辆和硬件系统&#xff0c;快速搭建一套属于自己的自动驾驶系统。 开放能力、共享资源、加速创新、持续共赢是 Apollo 开放平台的口号。百度把自己所拥有的强大、…...

一文看懂!数据管道和数据流在数据分析中的作用

当我们谈论数据分析时&#xff0c;我们通常会想到一系列的步骤&#xff0c;包括数据收集、数据清洗、数据分析和数据可视化等。然而&#xff0c;在这些步骤中&#xff0c;有两个非常重要的概念&#xff1a;数据管道和数据流。这两个概念在数据分析过程中起着至关重要的作用。本…...

Linux系统下检验Tensorflow 2.xx版本和1.xx版本是否安装成功

目录 版本问题Tensorflow 1.xx的测试代码&#xff1a;Tensorflow 2.xx的测试代码&#xff1a;Tensorflow 2.6版本实际的测验结果 总结 版本问题 查询资料发现&#xff0c;多数检验Tensorflow是否安装成功的方法&#xff0c;多数方法都是1.xx版本的&#xff0c;直接使用1.xx版本…...

暑期高铁站大量遗失物品,FindMy帮助寻找

近日&#xff0c;一女子在上海坐高铁时&#xff0c;将户口本、房产证遗落安检处的新闻引起网友的关注。然后业内人士表示&#xff1a;常事&#xff0c;车站什么都能捡到。 据中国铁路透露&#xff0c;暑运期间&#xff0c;上海虹桥站客流增加&#xff0c;日均发送旅客20多万人…...

通过安全日志读取WFP防火墙放行日志

前言 之前的文档中&#xff0c;描写了如何对WFP防火墙进行操作以及如何在防火墙日志中读取被防火墙拦截网络通讯的日志。这边文档&#xff0c;着重描述如何读取操作系统中所有被放行的网络通信行为。 读取系统中放行的网络通信行为日志&#xff0c;在win10之后的操作系统上&am…...

JDK、JRE、Java SE、Java EE和Java ME有什么区别?

Java现在已不仅仅是一种语言&#xff0c;从广义上说&#xff0c;它代表了一个技术体系。该体系根据应用方向的不同主要分为Java SE、Java EE和Java ME的3个部分。 1.SE(JavaSE)&#xff0c;standard edition&#xff0c;标准版&#xff0c;是我们通常用的一个版本&#xff0c;从…...

Neo4j之unwind基础

UNWIND 语句在 Cypher 查询中用于将列表&#xff08;数组&#xff09;中的元素逐个“展开”&#xff0c;从而将每个元素视为单独的行进行处理。它通常与 MATCH、CREATE、MERGE 等语句结合使用&#xff0c;用于对列表中的每个元素执行相应的操作。以下是一些常用的示例和解释&am…...

回归预测 | MATLAB实现SSA-SVM麻雀搜索算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现SSA-SVM麻雀搜索算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现SSA-SVM麻雀搜索算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基…...

深入探索代理技术:Socks5、IP代理与网络安全

在当今高度互联的世界中&#xff0c;代理技术在网络安全和爬虫等领域发挥着重要作用。本文将着重介绍Socks5代理、IP代理以及它们在网络安全与爬虫开发中的应用&#xff0c;旨在帮助读者深入理解这些技术&#xff0c;从而更好地应用于实际情境。 1. Socks5代理的特点与用途 S…...

Matlab 频谱图中如何设置频率刻度

Matlab 频谱图中如何设置频率刻度&#xff08;横坐标&#xff09; 1、概述 时域信号经FFT 变换后得到了频谱&#xff0c;在作图时还必须设置正确的频率刻度&#xff0c;这样才能从图中得到正确的结果。下面来介绍如何设置正确的频率刻度。 2、案例分析 有一个余弦信号&#…...

在线转换器有哪些优势?在线Word转PDF操作分享

我们如果想要将两者不同格式文件进行格式转换&#xff0c;就需要下载安装转换器。如果出门带的设备没有安装转换软件客户端&#xff0c;就无法使用&#xff0c;会比较麻烦。现在有了在线转换工具&#xff0c;只需要打开相应的网页就可使用&#xff0c;那么在线Word转PDF的操作是…...

2023国赛数学建模A题思路模型代码汇总 高教社杯

本次比赛我们将会全程更新思路模型及代码&#xff0c;大家查看文末名片获取 之前国赛相关的资料和助攻可以查看 2022数学建模国赛C题思路分析_2022国赛c题matlab_UST数模社_的博客-CSDN博客 2022国赛数学建模A题B题C题D题资料思路汇总 高教社杯_2022国赛c题matlab_UST数模社…...

vue3如何批量设置动态ref

示例如下&#xff1a; <template v-for"item in selectList"><el-select v-model"item.value" :ref"el > setRef(el, item)"><el-optionv-for"v in item.options":key"v.value":label"v.label"…...