记一次SpringCloud OpenFeign 服务调用传递 token @Async 上下文信息获取失败

一、场景

在异步方法中使用了feign调用,发现提示“您还未登录或登录已失效”。那原因很明了就是我的登录信息没办法传入到feign的调用方法里。
在这里插入图片描述

二、考虑的解决办法

1)尝试一:ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
sendAsyncService.statisticsSendSms(idList, userTokenValue, sendSMSNotificationParams, coreDescriptionParams, attributes);
public void statisticsSendSms(List<Long> reportIdList,UserTokenValue userTokenValue,SendSMSNotificationParams sendSMSNotificationParams,CoreDescriptionParams coreDescriptionParams,ServletRequestAttributes attributes) {// 设置子线程共享RequestContextHolder.setRequestAttributes(attributes, true);//figen 调用,需要tokenResponseResult<String> responseResult = smsApi.sendSMSNotification(sendSMSNotificationParams);

这种情况犹豫反复在测试环境测试,都无任何问题,心里自信满满,但是上线后,却暴漏了,依旧提示“您还未登录或登录已失效”。这是什么情况?

1-1)RequestContextHolder跨线程获取不到requests请求对象的原因

为何会失败呢?因为异步注解,顾名思义,是开启了一个新的线程去执行一些代码。
在这里插入图片描述
在这里插入图片描述

/*** 给当前线程绑定属性* @param inheritable 是否要将属性暴露给子线程* */
public static void setRequestAttributes(@Nullable RequestAttributes attributes, boolean inheritable) {if (attributes == null) {resetRequestAttributes();}else {if (inheritable) {inheritableRequestAttributesHolder.set(attributes);requestAttributesHolder.remove();}else {requestAttributesHolder.set(attributes);inheritableRequestAttributesHolder.remove();}}}

那源代码理解,已经将属性暴漏给子线程了,为何上线后依旧是获取不到呢?那其实从根本思考,主线程加入相应速度快于子线程呢,结果会是如何?结果就是主线程结束,所有的信息都已经销毁了,谁还管你子线程是否执行没执行呢,哈哈哈。测试环境未复现,是因为环境配置低,可能测试的几次都一定概率的主线程相应时间大于了子线程的相应时间,到了线上,由于高配置的环境,这种平衡性被打破了,主线程先行一步了。
缘由了解了,解决的办法也就来了----肯定就是让主线程等一下,等子线程执行完再结束,可是主线程会那么礼貌吗?该如何解决这个问题呢?

2)自定义异步线程池,配置中做相关处理

// 解决使用@Async注解,获取不到上下文信息的问题executor.setTaskDecorator(runnable -> {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();AsyncContext asyncContext;if (attributes!=null){HttpServletRequest request=attributes.getRequest();asyncContext=request.startAsync();} else {asyncContext = null;}return ()->{try {// 我们set 进去 ,其实是一个ThreadLocal维护的.RequestContextHolder.setRequestAttributes(attributes);runnable.run();}finally {RequestContextHolder.resetRequestAttributes();if (asyncContext!=null){asyncContext.complete();}}};});

2-1)Servlet的异步处理

是由AsyncContext接口来实现的。

AsyncContext asyncContext;if (attributes!=null){HttpServletRequest request=attributes.getRequest();asyncContext=request.startAsync();} else {asyncContext = null;}

2-3)异步注解使用了自定义线程池,避免一个方法多个异步注解使用

@Async("asyncServiceExecutor")
AsyncContext asyncContext;if (attributes!=null){HttpServletRequest request=attributes.getRequest();asyncContext=request.startAsync();} else {asyncContext = null;}

由于线程池中我们使用了Servlet的异步处理来 set我们需要的token信息,所以避免重复调用。多次调用会报错,即使不影响信息获取。
在Servlet中多次调用自定义线程池可能导致错误,这通常是因为Servlet的单实例模式导致的线程安全问题。Servlet容器通常会为每个Servlet维护一个实例,当多个请求同时访问同一个Servlet实例时,可能会出现竞态条件,比如多个线程尝试使用相同的资源或状态。

三、错误使用记录

1)java.lang.IllegalStateException: Calling [asyncStart()] is not valid for a request with Async state [STARTING]

在这里插入图片描述

1-1)报错解析:

表明你正在尝试对一个已经被dispatch()方法分派的异步请求执行asyncStart()操作,而这不被允许。
在Java的Servlet API中,异步处理允许请求处理过程中转移到其他线程继续执行,而不阻塞原始请求线程。当你调用request.startAsync()或request.getAsyncContext()时,会创建一个AsyncContext对象。在这个对象被分派之后,原始请求线程可能已经结束,而新的线程继续处理异步的任务。
解决这个问题的方法是确保在调用asyncStart()之前不要对AsyncContext进行分派操作。如果你需要在异步处理中启动新的线程,应该在调用request.startAsync()之后立即进行,并确保不会有进一步的分派发生。

2)解决办法:整个方法内只能允许一个异步调用,配置代码如上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/20693.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C语言进阶】文件操作:文件的打开与文件的读写以及文本文件和二进制文件

目录 1、为什么使用文件 2、什么是文件 2.1 程序文件 2.2 数据文件 2.3 文件名 3、文件的打开和关闭 3.1文件指针 3.2文件的打开与关闭 4、文件的顺序读写 4.1 几个函数的区别 5、文件随机读写 5.1 fseek 5.2 ftell 5.3 rewind 6、文本文件和二进制文件…

springboot+vue+mybatis超市管理-简单版+PPT+论文+讲解+售后

使用旧方法对超市信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在超市信息的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。 这次开发的小型超市管理系统有管理员&…

MyCat面试题及参考答案(3万字长文)

目录 什么是MyCat? MyCat的主要功能是什么? MyCat和MySQL Proxy有什么区别?

Java基础(5) 面向对象编程2

目录 一、关键词&#xff1a;this 1.定义 2.作用 &#xff08;1&#xff09;实例方法或构造器中使用当前对象的成员 &#xff08;2&#xff09;同一个类中构造器互相调用 二、方法的重写 1.定义 2.要求 3.代码 4.区分重载和重写 三、关键字&#xff1a;super 1.定义…

探索DIYGW可视化开发工具:提升UniApp项目效率与质量的新途径

一、引言 在快速迭代和不断创新的移动应用开发领域中&#xff0c;开发者们常常面临着一个共同的挑战&#xff1a;如何在保证开发质量的同时&#xff0c;缩短开发周期。近期&#xff0c;一款名为DIYGW的可视化开发工具进入了我们的视野&#xff0c;它以其独特的拖拽式开发方式和…

AI前沿技术探索:智能化浪潮下的创新与应用

一、引言 随着科技的不断进步&#xff0c;人工智能&#xff08;AI&#xff09;已成为推动社会发展的重要力量。从自动驾驶汽车到智能医疗诊断&#xff0c;从智能家居到虚拟助手&#xff0c;AI技术正逐渐渗透到我们生活的方方面面。本文旨在探讨AI的前沿技术、创新应用以及未来…

算法题-给定一个日期,输出星期几

目录 给定日期&#xff0c;输出对应是星期几 测试结果 如1900年 5月6日是星期三&#xff0c;计算给的日期是星期几 给定日期&#xff0c;输出对应是星期几 #include <stdio.h> #include <stdlib.h> #include <string.h>int main() {char input[100];int d…

TypeScript算法每日一题:两数之和(1)

作者&#xff1a;前端小王hs 阿里云社区博客专家/清华大学出版社签约作者✍/CSDN百万访问博主/B站千粉前端up主 题库&#xff1a;力扣 题目序号&#xff1a;1&#xff08;简单&#xff09; 题目&#xff1a; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该…

如何被谷歌收录?

最简单的方法就是提交网站给谷歌&#xff0c;但这种方法可操作空间不大&#xff0c;一天一般也就只有十条左右的链接可以提交&#xff0c;对于一些大网站来说&#xff0c;这种方法显然不适用&#xff0c;这时候GPC爬虫池的好处就体现了&#xff0c;GPC爬虫池对希望提升Google搜…

力扣每日一题 6/1

2928.给小朋友们分糖果[简单] 题目&#xff1a; 给你两个正整数 n 和 limit 。 请你将 n 颗糖果分给 3 位小朋友&#xff0c;确保没有任何小朋友得到超过 limit 颗糖果&#xff0c;请你返回满足此条件下的 总方案数 。 示例 1&#xff1a; 输入&#xff1a;n 5, limit 2 …

Deepin Linux 深度 V23 beige 官方源及换镜像源方法。

Deepin Linux 深度 V23 英文版本号&#xff1a;beige 谁起的烂名字。。。。。。 1. 打开文件管理器&#xff0c;在apt文件夹点右键&#xff08;以管理员身份打开&#xff09;&#xff0c; 2. 输入你的登录密码&#xff0c;以便打开文件夹&#xff08;管理员权限&#xff09;。…

【MySQL数据库】索引与事务

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【MySQL】探秘&#xff1a;数据库世界的瑞士军刀 目录 &#x1f5f3;️一.索引 &#x1f4ee;1.工作原理 &#x1f4ec;2.类型 &#x1f4ed;3.作用 &#x1f4ea;4.优缺点 &#x1f4eb;5.使用…

【Modelground】个人AI产品MVP迭代平台(2)——网站从0-1部署教程

文章目录 1.选购一台云服务器2. 购买域名3. 通过nginx部署静态网站4. 通过gitee在云服务器拉取代码5. ICP备案总结 1.选购一台云服务器 目前阿里云在促销&#xff0c;一台2核2GB内存3Mbps宽带的云服务器&#xff0c;一年只需要99元&#xff0c;学生更便宜&#xff0c;我认为这…

Java——处理键盘输入

在Java中&#xff0c;可以使用多种方式来处理键盘输入。最常用的一种方法是使用 Scanner 类&#xff0c;它位于 java.util 包中。 一、使用 Scanner 类处理键盘输入 1、具体操作步骤 1&#xff09;导入 Scanner 类 在开始编写代码之前&#xff0c;需要导入 java.util.Scann…

C++ 类与构造函数 三五法则

前言 本文介绍C中类的基础知识&#xff0c;介绍所有的构造函数&#xff0c;和什么时候应该该写哪些构造函数&#xff0c;并介绍经典的三五法则。 在C中&#xff0c;只是声明一个空类&#xff0c;不做任何事情的话&#xff0c;编译器会自动为你生成如下八个默认函数&#xff1…

mysql表GEOMETRY记录的读取与增加

两张表&#xff0c;均有GEOMETRY字段&#xff0c;合并成一张表。 直接读取记录并insert into 出错&#xff0c;需用AsText(SHAPE) 及 GeomFromText($v[1])转换 一、读取 $tStr "select OGR_FID,AsText(SHAPE),name,area,perimeter,cnty_,cnty_id,cnty_code,pyname,post…

CentOS8安装opensips-cli

环境&#xff1a;阿里云 操作系统CentOS8.5 opensips 3.x版本废弃了之前的配置管理脚本opensipsctl&#xff0c;引入了一个新的python工具叫opensips-cli。本文描述如何在CentOS8安装这个工具。 升级python CentOS 8默认的ptyhon版本是3.6。这不能满足opensips-cli的要求&…

信息化业务运维的必要性和重要性

随着信息技术的飞速发展&#xff0c;企业信息化已经成为提升竞争力的关键手段。然而&#xff0c;仅仅拥有先进的信息化系统并不足以保证企业的高效运转&#xff0c;对这些系统进行科学、有效的运维同样至关重要。本文将深入探讨信息化业务运维的必要性和重要性。 一、信息化业…

什么是股票,新手如何入门

股票是代表公司所有权的证券&#xff0c;当你持有某公司的股票时&#xff0c;你实际上拥有了该公司的一部分。作为股东&#xff0c;你有权分享公司的利润&#xff08;如通过股息&#xff09;&#xff0c;以及在公司解散时对公司剩余资产的索取权。以下是关于股票的一些基本概念…

【TB作品】MSP430F5529,单片机,电子秒表,秒表

硬件 MSP430F5529开发板7针0.96寸OLED /* OLED引脚分配 绿色板子DO(SCLK)------P4.3D1(DATA)------P4.0RES-----------P3.7DC------------P8.2CS------------P8.1 */ 程序功能 该程序是一个用C语言编写的&#xff0c;用于msp430f5529微控制器上的简单电子秒表应用。它使用…