应用场景

我们在使用一些开源调度系统(比如:elastic-job等)的时候,对于任务的执行时间通常都是有规律性的,可能是每隔半小时执行一次,或者每天凌晨一点执行一次。然而实际业务中还存在另外一种定时任务,它可能需要一些触发条件才开始定时,比如:编写博文时候,设置2小时之后发送。对于这些开始时间不确定的定时任务,我们也可以通过Spring Cloud Stream来很好的处理。

为了实现开始时间不确定的定时任务触发,我们将引入延迟消息的使用。RabbitMQ中提供了关于延迟消息的插件,所以本文就来具体介绍以下如何利用Spring Cloud Stream以及RabbitMQ轻松的处理上述问题。

动手试试

插件安装

关于RabbitMQ延迟消息的插件介绍可以查看官方网站:https://www.rabbitmq.com/blog...

安装方式很简单,只需要在这个页面:http://www.rabbitmq.com/commu... 中找到rabbitmq_delayed_message_exchange插件,根据您使用的RabbitMQ版本选择对应的插件版本下载即可。

注意:只有RabbitMQ 3.6.x以上才支持

在下载好之后,解压得到.ez结尾的插件包,将其复制到RabbitMQ安装目录下的plugins文件夹。

然后通过命令行启用该插件:

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

该插件在通过上述命令启用后就可以直接使用,不需要重启。

另外,如果您没有启用该插件,您可能为遇到类似这样的错误:

ERROR 156 --- [ 127.0.0.1:5672] o.s.a.r.c.CachingConnectionFactory : Channel shutdown: connection error; protocol method: #method(reply-code=503, reply-text=COMMAND_INVALID - unknown exchange type 'x-delayed-message', class-id=40, method-id=10)

应用编码

下面通过编写一个简单的例子来具体体会一下这个属性的用法:

@EnableBinding(TestApplication.TestTopic.class)
@SpringBootApplication
public class TestApplication {public static void main(String[] args) {SpringApplication.run(TestApplication.class, args);}@Slf4j@RestControllerstatic class TestController {@Autowiredprivate TestTopic testTopic;/*** 消息生产接口** @param message* @return*/@GetMapping("/sendMessage")public String messageWithMQ(@RequestParam String message) {log.info("Send: " + message);testTopic.output().send(MessageBuilder.withPayload(message).setHeader("x-delay", 5000).build());return "ok";}}/*** 消息消费逻辑*/@Slf4j@Componentstatic class TestListener {@StreamListener(TestTopic.INPUT)public void receive(String payload) {log.info("Received: " + payload);}}interface TestTopic {String OUTPUT = "example-topic-output";String INPUT = "example-topic-input";@Output(OUTPUT)MessageChannel output();@Input(INPUT)SubscribableChannel input();}}

内容很简单,既包含了消息的生产,也包含了消息消费。在/sendMessage接口的定义中,发送了一条消息,一条消息的头信息中包含了x-delay字段,该字段用来指定消息延迟的时间,单位为毫秒。所以上述代码发送的消息会在5秒之后被消费。在消息监听类TestListener中,对TestTopic.INPUT通道定义了@StreamListener,这里会对延迟消息做具体的逻辑。由于消息的消费是延迟的,从而变相实现了从消息发送那一刻起开始的定时任务。

在启动应用之前,还要需要做一些必要的配置,下面分消息生产端和消费端做说明:

消息生产端

spring.cloud.stream.bindings.example-topic-output.destination=delay-topic
spring.cloud.stream.rabbit.bindings.example-topic-output.producer.delayed-exchange=true

注意这里的一个新参数spring.cloud.stream.rabbit.bindings.example-topic-output.producer.delayed-exchange,用来开启延迟消息的功能,这样在创建exchange的时候,会将其设置为具有延迟特性的exchange,也就是用到上面我们安装的延迟消息插件的功能。

消息消费端

spring.cloud.stream.bindings.example-topic-input.destination=delay-topic
spring.cloud.stream.bindings.example-topic-input.group=test
spring.cloud.stream.rabbit.bindings.example-topic-input.consumer.delayed-exchange=true

在消费端也一样,需要设置spring.cloud.stream.rabbit.bindings.example-topic-output.producer.delayed-exchange=true。如果该参数不设置,将会出现类似下面的错误:

ERROR 9340 --- [ 127.0.0.1:5672] o.s.a.r.c.CachingConnectionFactory       : Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - inequivalent arg 'type' for exchange 'delay-topic' in vhost '/': received 'topic' but current is ''x-delayed-message'', class-id=40, method-id=10)

完成了上面配置之后,就可以启动应用,并尝试访问localhost:8080/sendMessage?message=hello接口来发送一个消息到MQ中了。此时可以看到类似下面的日志:

2019-01-02 23:28:45.318  INFO 96164 --- [ctor-http-nio-3] c.d.s.TestApplication$TestController     : Send: hello
2019-01-02 23:28:45.328  INFO 96164 --- [ctor-http-nio-3] o.s.a.r.c.CachingConnectionFactory       : Attempting to connect to: [localhost:5672]
2019-01-02 23:28:45.333  INFO 96164 --- [ctor-http-nio-3] o.s.a.r.c.CachingConnectionFactory       : Created new connection: rabbitConnectionFactory.publisher#5c5f9a03:0/SimpleConnection@3278a728 [delegate=amqp://guest@127.0.0.1:5672/, localPort= 53536]
2019-01-02 23:28:50.349  INFO 96164 --- [ay-topic.test-1] c.d.stream.TestApplication$TestListener  : Received: hello

从日志中可以看到,Send: helloReceived: hello两条输出之间间隔了5秒,符合我们上面编码设置的延迟时间。

深入思考

在代码层面已经完成了定时任务,那么我们如何查看延迟的消息数等信息呢?

此时,我们可以打开RabbitMQ的Web控制台,首先可以进入Exchanges页面,看看这个特殊exchange,具体如下:

可以看到,这个exchange的Type类型是x-delayed-message。点击该exchange的名称,进入详细页面,就可以看到更多具体信息了:

代码示例

本文示例读者可以通过查看下面仓库的中的stream-delayed-message项目:

  • Github
  • Gitee

如果您对这些感兴趣,欢迎star、follow、收藏、转发给予支持!

以下专题教程也许您会有兴趣

  • Spring Boot基础教程
  • Spring Cloud基础教程

本文首发于我的独立博客:http://blog.didispace.com/spr...

Spring Cloud Stream 使用延迟消息实现定时任务(RabbitMQ)相关推荐

  1. spring cloud stream kafka 处理消息

    spring cloud stream kafka <dependency><groupId>org.springframework.cloud</groupId> ...

  2. Spring Cloud Stream消息中间件通过RabbitMQ实现消息推送

    一.Spring Cloud Stream是什么 Spring Cloud Stream 是一个构建消息驱动微服务的框架. Spring Cloud Stream解决了开发人员无感知的使用消息中间件的 ...

  3. Spring Cloud Stream Binder 实现

    Spring Cloud Stream Binder 实现 JMS 实现 ActiveMQ 1.增加Maven依赖 <!-- 整合 Sprig Boot Starter ActiveMQ --& ...

  4. 【本人秃顶程序员】使用Spring Cloud Stream和RabbitMQ实现事件驱动的微服务

    ←←←←←←←←←←←← 快!点关注 让我们展示如何使用Spring Cloud Stream来设计事件驱动的微服务.首先,Spring Cloud Stream首先有什么好处?因为Spring AM ...

  5. Spring Cloud Stream消费失败后的处理策略(四):重新入队(RabbitMQ)

    应用场景 之前我们已经通过<Spring Cloud Stream消费失败后的处理策略(一):自动重试>一文介绍了Spring Cloud Stream默认的消息重试功能.本文将介绍Rab ...

  6. 使用Spring Cloud Stream与RabbitMQ集成

    在我以前的文章中,我写了两个系统之间非常简单的集成场景-一个生成一个工作单元,另一个处理该工作单元,以及Spring Integration如何使这种集成非常容易. 在这里,我将演示如何使用Sprin ...

  7. 介绍一下关于Spring Cloud Stream

    Spring Cloud Stream是构建消息驱动的微服务应用程序的框架.Spring Cloud Stream基于Spring Boot建立独立的生产级Spring应用程序,并使用Spring I ...

  8. 【进阶技术】一篇文章搞掂:Spring Cloud Stream

    本文总结自官方文档http://cloud.spring.io/spring-cloud-static/spring-cloud-stream/2.1.0.RC3/single/spring-clou ...

  9. Spring Cloud Stream同一通道根据消息内容分发不同的消费逻辑

    应用场景 有的时候,我们对于同一通道中的消息处理,会通过判断头信息或者消息内容来做一些差异化处理,比如:可能在消息头信息中带入消息版本号,然后通过if判断来执行不同的处理逻辑,其代码结构可能是这样的: ...

最新文章

  1. visual studio 工具箱(选项卡、无控件、灰图标)
  2. python基础代码-python基础知识和练习代码
  3. 博客转移至:www.bugsafe.cn
  4. php实战https请求,用php发https请求
  5. python 打开txt_在python中从txt文件打开链接
  6. D. Flowers
  7. CSS的一些常用知识点
  8. 深圳最新10区地图划分JSON
  9. Postman安装失败,解决方法
  10. emmagee测试汇总
  11. The COMMIT TRANSACTION request has no corresponding BEGIN
  12. TP5 生成微信小程序海报图
  13. 重装系统Windows10纯净版操作步骤(微pe)
  14. 开始绘制立体图形立方体正四面体
  15. 计算机实训前言研究内容,计算机专业实践论文提纲模板 计算机专业实践论文提纲怎样写...
  16. NPN和PNP 的电流方向 、大小关系 、电压偏置
  17. 贫穷不可怕,贫穷的思维才最可怕
  18. 9_用户的登录和登出
  19. c语言需要数学英语,学C语言需要数学和英语吗?
  20. 如何设计 QQ、微信等第三方账号登陆 ?(附表设计)

热门文章

  1. 《SpringMVC数据绑定入门》笔记
  2. 通过分析 JDK 源代码研究 Hash 存储机制
  3. android SDK manager 无法获取更新版本列表【转载】
  4. iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(一)
  5. asp之GetArray提取链接地址,以$Array$分隔的代码
  6. 局部和匿名类型作模板实参
  7. glutSwapBuffers函数用法
  8. linux(1)- 简单的 shell 解释器
  9. 动态二维数组赋值及for循环遍历和toString遍历
  10. 云服务时代,你是否没穿内裤在到处逛啊!