使用消息队列扩展异步执行的实现方式
背景
你可能在你的项目中用过Spring的@Async注解,以此来将部分方法转化为异步执行,从而提高请求的响应效率
但在服务架构不断的演进之中,这种丢入线程池处理的方式带来的缺陷也愈发明显:
- 不利于监控
- 如果意外停机,尚未处理的任务会尽数丢失
- 在集群中的某个节点要处理大量异步任务时,无法将压力分担到集群中其他节点
- 项目中若集成了使用ThreadLocal特性的模块或第三方组件,需要注意上下文丢失的问题
思路
使用消息队列作为异步任务的实现方式,这样我们就可以:
- 大量成熟的MQ中间件都提供了可视化管理平台,监控更加方便
- 可以用消息队列Header来保存上下文,如用户信息、token等
- 消息队列的发布-订阅模式可以最大程度利用集群的业务处理能力
- 更容易保证任务的顺序性
- 如果有服务节点宕机,可以利用消息确认、消息重试等机制保证任务执行的正确性
实现
为了保证业务代码和实现方案解耦,类似于@Aync方案,我们同样采用注解+拦截器的方式进行逻辑注入
@Around("@annotation(org.springframework.amqp.rabbit.annotation.RabbitListener)") public Object cut(ProceedingJoinPoint pjp) throws Throwable { ... }
实现思路大同小异,就是读取注解中的队列声明确认发布-订阅关系,然后以丢入消息队列来替换丢入线程池
private String resolveKey(Queue[] queues) { String s = this.beanFactory.resolveEmbeddedValue(queues[0].value()); return (String) resolver.evaluate(s, evalContext); }
rabbitTemplate.convertAndSend(resolveKey(queues), args[0]);
为消息队列注入Json转换器,方便对象传输
@Bean public Jackson2JsonMessageConverter producerJackson2MessageConverter() { return new Jackson2JsonMessageConverter(); }
如有需要,我们可以将上下文的用户信息、token等写入消息的Header中
private MessagePostProcessor beforePublishPostProcessor() { return message -> { // setting up context to message header return message; }; }
被异步调用的service代码:
@Service @Slf4j public class DemoService { @RabbitListener(queuesToDeclare = @Queue("mytestqueue")) public void checkSome(List<String> tagTuple) { log.warn("check here {}", tagTuple); } }
调用service的controller:
@RestController public class DemoController { @Autowired private DemoService demoService; @RequestMapping("check") public Integer checkSome() { ArrayList<String> tagTuple = new ArrayList<>(); tagTuple.add("bar"); tagTuple.add("foo"); demoService.checkSome(tagTuple); return 0; } }
执行查看效果
17:00:14.584TRACE[AbstractHandlerMapping.java:411]Mapped to org.smop.duplex.sample.DemoController#checkSome() 17:00:21.263WARN [DemoService.java:16]check here [bar, foo]
如有帮助或启发,还请点个👍
附代码仓库:

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
如何在中文场景文字识别赛中赢取飞桨周边?
【飞桨开发者说】魏宏炜,福建省三明学院,本科三年级,研究方向为目标检测、OCR识别。 赛题背景 关于光学字符识别(Optical Character Recognition, 简称OCR),是指将图像上的文字转化为计算机可编辑的文字内容,众多的研究人员对相关的技术研究已久,也有不少成熟的OCR技术和产品产生,比如PaddleOCR。中文汉字识别是OCR的一个分支。因为汉语作为我们的母语,汉字主要在我国广泛使用,对汉字的种类、内涵、造字原理国内的掌握情况较透彻,所以关于汉字识别的深入研究主要集中在国内。 中文场景文字识别技术在人们的日常生活中受到广泛关注,具有丰富的应用场景,如:拍照翻译、图像检索、场景理解等。然而,中文场景中的文字面临着包括光照变化、低分辨率、字体以及排布多样性、中文字符种类多等复杂情况。如何解决上述问题成为一项极具挑战性的任务。 在本月中文场景文字识别赛中,笔者使用了飞桨开源深度学习框架,在百度学习与实训社区AI Studio上完成了数据处理、模型搭建、模型训练、模型预测等整个工作过程,拿到了6月份前十名,获得了800元京东卡。非常感谢AI Studio为参赛选手...
- 下一篇
后台高性能服务器设计的常见套路, BAT 高频面试
前言 在互联网公司,经常面临一个“三高”问题: 高并发 高性能 高可用 这篇文章将总结一下后台服务器开发中有哪些常用的解决“三高”问题的方法和思想。 希望这些知识,能够给你一丝启发和帮助,助力你收割 各大公司 Offer~ 先上本文思维导图: 正文 一、缓存 什么是缓存?看看维基百科怎么说: > In computing, a cache is a hardware or software component that stores data so that future requests for that data can be served faster; the data stored in a cache might be the result of an earlier computation or a copy of data stored elsewhere. 在计算机中,缓存是存储数据的硬件或软件组件,以便可以更快地满足将来对该数据的请求。 存储在缓存中的数据可能是之前计算结果,也可能是存储在其他位置的数据副本。 缓存本质来说是使用空间换时间的思想,它在计算机世界...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Windows10,CentOS7,CentOS8安装Nodejs环境
- MySQL8.0.19开启GTID主从同步CentOS8
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Hadoop3单机部署,实现最简伪集群
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果