当前位置:网站首页>采用注解+拦截器的方式进行异步执行的实现方式
采用注解+拦截器的方式进行异步执行的实现方式
2020-11-08 20:18:00 【osc_03803522】
背景
你可能在你的项目中用过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]
外部文件操作django的models
#外部文件使用django的models,需要配置django环境
import os
if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "singletablehw.settings")
import django
django.setup()
from app01 import models
import datetime
obj_list = []
for i in range(1,10):
obj = models.Book(
title='葵花宝典第%s式'%i,
price=20 + i,
pub_date='198%s-11-11 00:00:00'%i,
# pub_date=datetime.datetime.now(),
publish= '吴老板出版社' if i < 5 else '太白出版社',
)
obj_list.append(obj)
models.Book.objects.bulk_create(obj_list)
url别名反向解析
#添加书籍
url(r'^add_book/', views.add_book,name='abook'), #name='abook' 别名
# 删除书籍
url(r'^delete_book/(\d+)/', views.delele_book,name='delete_book'),
视图:
from django.urls import reverse
reverse('别名') reverse('abook') -- /add_book/ #不带参数的
print(reverse('delete_book',args=(71,))) #/delete_book/71/ 带参数的
模板:
{% url 'abook' %} 无参数的
{% url 'delete_book' book.id %} 有参数的
版权声明
本文为[osc_03803522]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/4797210/blog/4708314
边栏推荐
猜你喜欢

Flink's sink: a preliminary study

进程 线程 协程

Problem solving templates for subsequence problems in dynamic programming

Looking for a small immutable dictionary with better performance

VirtualBox安装centos7

CountDownLatch 瞬间炸裂!同基于 AQS,凭什么 CyclicBarrier 可以这么秀?

Looking for better dynamic getter and setter solutions

C + + opencv4.3 sift matching

Django's simple user system (3)

abp(net core)+easyui+efcore实现仓储管理系统——出库管理之五(五十四)
随机推荐
Suffix expression to infix expression
使用Fastai开发和部署图像分类器应用
使用基于GAN的过采样技术提高非平衡COVID-19死亡率预测的模型准确性
How much faster is a server equipped with a SSD than a mechanical hard disk
如何将PyTorch Lightning模型部署到生产中
第二章编程练习
SQL quick query
AI perfume is coming. Will you buy it?
MongoDB数据库
c++ opencv4.3 sift匹配
Using fastai to develop and deploy image classifier application
Dynamic planning
Server side resolution of lengthfieldbasedframedecoder of GetBytes
What is forsage Ethereum smart contract? What is the global decline of Ethereum
PAT_甲级_1056 Mice and Rice
Creating a text cloud or label cloud in Python
Creating a text cloud or label cloud in Python
LeetCode 45 跳跃游戏II
单例模式的五种设计方案
趣文分享:C 语言和 C++、C# 的区别在什么地方?