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

Feign异步模式丢失上下文问题

Feign异步模式丢失上下文问题

问题描述

当我们使用异步对我们代码进行操作优化时,代码中使用了RequestContextHolder去获取上下文的数据,当我们执行原来可以执行的业务时发现报了空指针异常或数据为空,这是为什么呢?

image-20250516193327144

原理解释

通过源码我们可以看出来,RequestContextHolder本质的是使用了ThreadLocal作为上下文的实现方式,但ThreadLocal只在自己线程中才可以读取到数据,但我们开启了异步线程,导致数据在不同的线程中为空,那我们怎么解决呢?

image-20250516193412987

解决方法

1、在主线程中读取出主线程的数据,通过RequestContextHolder将数据注入到子线程中即可解决此问题

@Overridepublic OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {OrderConfirmVo confirmVo = new OrderConfirmVo();MemberLoginTo memberLoginTo = loginToThreadLocal.get();System.out.println("主线程的id:"+Thread.currentThread().getId());// 主线程的threadLocal数据,注意threadLocal中的数据只是在本线程中生效,若启用异步线程则会出现线程读取不到数据的问题RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();// 1、远程查询所有的收货地址的列表CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {// 将主线程的threadLocal共享到子线程,避免出现读取不到子线程上下文数据的问题System.out.println("当前线程的id:"+Thread.currentThread().getId());RequestContextHolder.setRequestAttributes(requestAttributes);List<MemberAddressVo> address = memberFeignService.getAddress(memberLoginTo.getId());confirmVo.setAddress(address);}, executor);CompletableFuture<Void> CartItemFuture = CompletableFuture.runAsync(() -> {// 2、远程查询购物车的购物项列表// 将主线程的threadLocal共享到子线程,避免出现读取不到子线程上下文数据的问题System.out.println("当前线程的id:"+Thread.currentThread().getId());RequestContextHolder.setRequestAttributes(requestAttributes);List<OrderItemVo> userCartItems = cartFeignService.getUserCartItems();confirmVo.setOrderItems(userCartItems);// feign 在远程调用之前要构造请求,会调用很多的拦截器}, executor);return confirmVo;}

2、在主线程中使用RequestContextHolder.setRequestAttributes(requestAttributes,true);将主线程的数据共享即可解决此问题

@Overridepublic OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {OrderConfirmVo confirmVo = new OrderConfirmVo();MemberLoginTo memberLoginTo = loginToThreadLocal.get();System.out.println("主线程的id:"+Thread.currentThread().getId());// 主线程的threadLocal数据,注意threadLocal中的数据只是在本线程中生效,若启用异步线程则会出现线程读取不到数据的问题RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();// 开启线程数据共享RequestContextHolder.setRequestAttributes(requestAttributes,true);// 1、远程查询所有的收货地址的列表CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {// 将主线程的threadLocal共享到子线程,避免出现读取不到子线程上下文数据的问题System.out.println("当前线程的id:"+Thread.currentThread().getId());
//            RequestContextHolder.setRequestAttributes(requestAttributes);List<MemberAddressVo> address = memberFeignService.getAddress(memberLoginTo.getId());confirmVo.setAddress(address);}, executor);CompletableFuture<Void> CartItemFuture = CompletableFuture.runAsync(() -> {// 2、远程查询购物车的购物项列表// 将主线程的threadLocal共享到子线程,避免出现读取不到子线程上下文数据的问题System.out.println("当前线程的id:"+Thread.currentThread().getId());
//            RequestContextHolder.setRequestAttributes(requestAttributes);List<OrderItemVo> userCartItems = cartFeignService.getUserCartItems();confirmVo.setOrderItems(userCartItems);// feign 在远程调用之前要构造请求,会调用很多的拦截器}, executor);return confirmVo;}

要构造请求,会调用很多的拦截器
}, executor);
return confirmVo;
}


相关文章:

  • 探索ISBN查询接口:为图书管理系统赋能
  • 三格电子上新了——IO-Link系列集线器
  • 1-10 目录树
  • 【控制波形如何COPY并无痛使用】
  • NocoBase 本周更新汇总:优化及缺陷修复
  • VSCode插件 —— 文心快码 BAIDU COMATE (免费!!)
  • 代码随想录第51天|岛屿数量(深搜)、岛屿数量(广搜)、岛屿的最大面积
  • windows编程中加载DLL的两种典型方式的比较
  • 内部检测实验室数字化转型新路径 质检LIMS系统如何实现合规、效率、资质三重突破?
  • 小结:JavaScript 模块化工具链
  • 日志与策略模式
  • 针对面试-微服务篇
  • Android应用内存分析与优化 - 工具篇之Booster
  • 安科瑞DJSF1352-D直流电能表:破解充电桩计量难题
  • Spring Boot 封装 MinIO 工具
  • 5.16本日总结
  • 物联网僵尸网络防御:从设备认证到流量染色
  • Redis解析
  • Axure设计的“广东省网络信息化大数据平台”数据可视化大屏
  • 软件测试—接口测试面试题及jmeter面试题
  • 孟夏韵评《无序的学科》丨误读与重构的文化漂流
  • 联合国:欢迎俄乌伊斯坦布尔会谈,希望实现全面停火
  • 广西百色“致富果”:高品质芒果直供香港,带动近五千户增收
  • 贝壳一季度收入增长42%:二手房市场活跃度维持在高位
  • 国防部:中方愿与俄方不断增强两军关系良好发展势头
  • 美将解除对叙利亚制裁,外交部:中方一贯反对非法单边制裁