【Spring Cloud】feign调用携带token

当我们再用feign调用的时候,如果对应服务需要token验证则需要我们传递token

网上提供的方法都是添加如下配置:

@Configuration
public class FeignConfig implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            requestTemplate.header("token", request.getHeader("token"));
        }
    }

}

但是使用这个的时候由于fegin是使用子线程调用的,导致获取到的attributes不存在,所以我们要使用可继承的InheritableThreadLocal来保存

默认如下所示

public class RequestContextListener implements ServletRequestListener {

	private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
			RequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";


	@Override
	public void requestInitialized(ServletRequestEvent requestEvent) {
		if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
			throw new IllegalArgumentException(
					"Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
		}
		HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
		ServletRequestAttributes attributes = new ServletRequestAttributes(request);
		request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
		LocaleContextHolder.setLocale(request.getLocale());
		RequestContextHolder.setRequestAttributes(attributes); // 保存attributes
	}
}

//  RequestContextHolder
/**
 * Bind the given RequestAttributes to the current thread,
 * <i>not</i> exposing it as inheritable for child threads.
 * @param attributes the RequestAttributes to expose
 * @see #setRequestAttributes(RequestAttributes, boolean)
 */
public static void setRequestAttributes(@Nullable RequestAttributes attributes) {
	setRequestAttributes(attributes, false); // inheritable 默认为false
}

所以要使用如下方法重新执行一下

public class MyRequestContextListener implements ServletRequestListener {


    private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
            MyRequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";

    /**
     * 初始化
     *
     * @param requestEvent Information about the request
     */
    @Override
    public void requestInitialized(ServletRequestEvent requestEvent) {
        if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
            throw new IllegalArgumentException(
                    "Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
        }
        HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
        ServletRequestAttributes attributes = new ServletRequestAttributes(request);
        request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
        LocaleContextHolder.setLocale(request.getLocale());
        RequestContextHolder.setRequestAttributes(attributes, true);
    }
	...
}

InheritableThreadLocal也有局限性,即后续父线程数据更改的时候不会在子线程进行同步

tips: InheritableThreadLocal 由于InheritableThreadLocal 是只有在线程初始化的时候才会进行初始化复制,所以后续父线程数据更改的时候不会进行同步,如下所示


private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
					  
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
			
}

// inheritThreadLocals为True时  构造一个新映射,包括来自给定父映射的所有可继承 ThreadLocal。仅由 createInheritedMap 调用。
private ThreadLocalMap(ThreadLocalMap parentMap) {
	Entry[] parentTable = parentMap.table;
	int len = parentTable.length;
	setThreshold(len);
	table = new Entry[len];

	for (int j = 0; j < len; j++) {
		Entry e = parentTable[j];
		if (e != null) {
			@SuppressWarnings("unchecked")
			ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
			if (key != null) {
				Object value = key.childValue(e.value);
				Entry c = new Entry(key, value);
				int h = key.threadLocalHashCode & (len - 1);
				while (table[h] != null)
					h = nextIndex(h, len);
				table[h] = c;
				size++;
			}
		}
}

由此,可以对以上方法进行升级一步到位,集成阿里的TransmittableThreadLocal

public class CrmRequestContextHolder {

	private static final TransmittableThreadLocal<RequestAttributes> requestAttributesHolder =
			new TransmittableThreadLocal<>();


	public static void resetRequestAttributes() {
		requestAttributesHolder.remove();
	}


	public static void setRequestAttributes(@Nullable RequestAttributes attributes) {
		if (attributes == null) {
			resetRequestAttributes();
		} else {
			requestAttributesHolder.set(attributes);
		}
	}

	@Nullable
	public static RequestAttributes getRequestAttributes() {
		return requestAttributesHolder.get();
	}

}

public class MyRequestContextListener implements ServletRequestListener {


    private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
            MyRequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";

    /**
     * 初始化
     *
     * @param requestEvent Information about the request
     */
    @Override
    public void requestInitialized(ServletRequestEvent requestEvent) {
        if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
            throw new IllegalArgumentException(
                    "Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
        }
        HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
        ServletRequestAttributes attributes = new ServletRequestAttributes(request);
        request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
        LocaleContextHolder.setLocale(request.getLocale());
        CrmRequestContextHolder.setRequestAttributes(attributes);
    }
	...
}

tips: 由于feign的线程没有被Ttl装饰,所以只有继承性,没有全局关联性,等同于InheritableThreadLocal,若需要对应功能需要确保Feign线程正确地使用了TTL装饰器。实现如下

重写HystrixConcurrencyStrategy

@Slf4j
public class CrmHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {

	private static final CrmHystrixConcurrencyStrategy INSTANCE = new CrmHystrixConcurrencyStrategy();

	public static HystrixConcurrencyStrategy getInstance() {
		return INSTANCE;
	}

	private CrmHystrixConcurrencyStrategy() {
	}


	private static ThreadFactory getThreadFactory(final HystrixThreadPoolKey threadPoolKey) {
		return !PlatformSpecific.isAppEngineStandardEnvironment() ? new ThreadFactory() {
			private final AtomicInteger threadNumber = new AtomicInteger(0);

			public Thread newThread(Runnable r) {
				// 此处使用Ttl包装
				Thread thread = new Thread(TtlRunnable.get(r), "ttlHr-" + threadPoolKey.name() + "-" + this.threadNumber.incrementAndGet());
				thread.setDaemon(true);
				return thread;
			}
		} : PlatformSpecific.getAppEngineThreadFactory();
	}
}

重置策略

HystrixPlugins.getInstance().registerConcurrencyStrategy(CrmHystrixConcurrencyStrategy.getInstance());

查看 效果
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

flowable-ui部署

版本 java: java8+tomcat: apache-tomcat-9.0.87flowable: flowable-6.8.1mysql驱动: mysql-connector-java-8.0.30.jar 注意:版本一定要对,否则启动报错执行数据库脚本 创建数据库flowable执行脚本,脚本位于解压flowable-6.8.1.zip后的flowable-6.8.1/database/create/all/…

2024图表分析网页模版大数据可视化大屏电子沙盘合集包含金融行业智慧大厅智慧交通智慧门店智慧物流智慧小区

2024图表分析网页模版大数据可视化大屏电子沙盘合集包含金融行业智慧大厅智慧交通智慧门店智慧物流智慧小区 项目介绍&#xff1a; 图表分析网页模版 大数据可视化大屏电子沙盘合集&#xff0c;项目基于html/css/js&#xff0c;包含行业&#xff1a; 智慧政务 智慧社区 金融行…

如何高效接入 Flink: Connecter / Catalog API 核心设计与社区进展

本文整理自阿里云实时计算团队 Apache Flink Committer 和 PMC Member 任庆盛在 FFA 2023 核心技术专场&#xff08;二&#xff09;中的分享&#xff0c;内容主要分为以下四部分&#xff1a; Source APISink API将 Connecter 集成至 Table /SQL APICatalog API 在正式介绍这些 …

100天精通Python(实用脚本篇)——第118天:基于selenium和ddddocr库实现反反爬策略之验证码识别

文章目录 专栏导读一、前言二、ddddocr库使用说明1. 介绍2. 算法步骤3. 安装4. 参数说明5. 纯数字验证码识别6. 纯英文验证码识别7. 英文数字验证码识别8. 带干扰的验证码识别 三、验证码识别登录代码实战1. 输入账号密码2. 下载验证码3. 识别验证码并登录 书籍推荐 专栏导读 …

TCP-IP 知识汇总

开放式系统互联模型------国际化标准组织ISO提出----协议组&#xff08;协议模型&#xff09; 应用层&#xff1a;接收用户数据&#xff0c;人机交互的接口 表示层&#xff1a;将编码转换为二进制&#xff08;加密、解密&#xff09;---统一格式 会话层&#xff1a;针对传输…

Docker进阶:离线安装docker社区版(docker-18.06.3-ce)

Docker进阶&#xff1a;离线安装docker社区版&#xff08;docker-18.06.3-ce&#xff09; 1、准备离线安装所需的文件2、传输文件至目标Linux系统3、卸载旧版Docker4、离线安装Docker1、解压上传的Docker安装包2、拷贝文件到/usr/bin目录3、将 Docker 注册为系统服务4、重新加载…

linux 使用docker安装 postgres 教程,踩坑实践

linux 使用docker安装 postgres 教程 踩坑实践,安装好了不能远程访问。 防火墙已关闭、postgres 配置了允许所有ip 访问、网络是通的。端口也是开放的&#xff0c;就是不能用数据库链接工具访问。 最后发现是云服务器端口没开 ,将其打开 到这一步完全正确了&#xff0c;但是…

如何培养员工应用六西格玛解决问题的能力?

近年来&#xff0c;为了提高工作效率和产品质量&#xff0c;许多企业开始引入六西格玛管理方法。然而&#xff0c;仅仅引入六西格玛并不足以确保成功&#xff0c;培养员工应用六西格玛解决问题的能力才是关键。那么&#xff0c;如何培养员工应用六西格玛解决问题的能力呢&#…

【强化学习】安装gym==0.18.3报错的解决方法

安装gym0.18.3报错的解决方法 Collecting gym0.18.3 Using cached gym-0.18.3.tar.gz (1.6 MB) Preparing metadata (setup.py) … error error: subprocess-exited-with-error python setup.py egg_info did not run successfully. │ exit code: 1 ╰─> [1 lines of o…

Linux查看进程的一些方法

ps ps &#xff08;英文全拼&#xff1a;process status&#xff09;命令用于显示当前进程的状态&#xff0c;类似于 windows 的任务管理器。可以搭配kill指令随时中断、删除不必要的程序。ps命令是最基本同时也是非常强大的进程查看命令&#xff0c;使用该命令可以确定有哪些…

第111讲:Mycat实践指南:固定Hash算法分片下的水平分表详解

文章目录 1.固定Hash算法分片的概念1.1.固定Hash算法的概念1.2.固定Hash算法是如何将数据路由到分片节点的 2.使用固定Hash算法分片对某张表进行水平拆分2.1.在所有的分片节点中创建表结构2.2.配置Mycat实现固定Hash算法分片的水平分表2.2.1.配置Schema配置文件2.2.2.配置Rule分…

微信开发者工具如何使用?使用注意事项

&#xff08;1&#xff09;单位如何进行换算&#xff1f; 1 px 750/屏幕宽度 rpx 1 rpx 屏幕宽度/750 px &#xff08;2&#xff09;如何新建文件&#xff1f; 1> 点开app.json 2> 在“pages/index/index”后面接“&#xff0c;pages/自定义文件夹名/自定义文件名”…

FPGA 学习需要哪些东西?

FPGA 学习需要哪些东西&#xff1f; 三样东西&#xff1a;第一就是完整的理论&#xff0c;第二一套开发板&#xff0c;第三可练手的项目 第一&#xff0c;一套完整的课程&#xff0c; 这个课程必须是紧跟技术发展的&#xff0c;适应市场的&#xff0c;这样不至于学完后发现太…

开源Ai对话系统(MNAi)系统

支持对接gpt&#xff0c;阿里云&#xff0c;腾讯云/chatGPT源码/AI绘画系统/AI创作系统/AI写作系统 具体看截图 后端环境&#xff1a;PHP7.4MySQL5.6 软件&#xff1a;uniapp 部署教程请看源码内的【使用教程】文档 源码免费下载地址抄笔记 chaobiji.cn

【计算机网络篇】物理层(3)编码与调制

文章目录 &#x1f354;编码与调试⭐基本概念 &#x1f354;基本的带通调制方法和混合调制方法⭐基本的带通调制方法⭐混合调制方法 &#x1f354;编码与调试 物理层是OSI模型中的第一层&#xff0c;它负责在物理媒体上传输原始比特流。在物理层的编码和调试中&#xff0c;我们…

leetcode106从中序与后序遍历序列构造二叉树

目录 1.解题关键2.思路3.变量名缩写与英文单词对应关系4.算法思路图解5.代码 本文针对原链接题解的比较晦涩的地方重新进行说明解释 原题解链接&#xff1a;https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/solutions/50561/tu-jie-…

3D Tiles语义分割流水线

Dylan Chua 和 Anne Lee 开发了一个处理管线&#xff0c;用于对 3D Tiles 中包含的 GL 传输格式 (glTF) 模型进行语义分割。 该管道读取并遍历 3D Tileset&#xff0c;以输出包含元数据的经过转换的划分对象集。 该项目为 3D 语义分割器提供了最小可行产品&#xff0c;作为各种…

STM32CubeIDE基础学习-BEEP蜂鸣器实验

STM32CubeIDE基础学习-BEEP蜂鸣器实验 文章目录 STM32CubeIDE基础学习-BEEP蜂鸣器实验前言第1章 硬件介绍第2章 工程配置2.1 工程外设配置部分2.2 生成工程代码部分 第3章 代码编写第4章 实验现象总结 前言 前面学习了LED闪烁实验&#xff0c;现在来学习一下蜂鸣器发声实验&am…

JVM工作原理与实战(四十四):JVM常见面试题目

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、JVM常见面试题目 1.有哪些常用的垃圾回收器&#xff1f; 2.什么是内存泄漏&#xff0c;如何解决内存泄漏问题&#xff1f; 3.请列举并简要描述一些常用的JVM工具及其主要功能。 …

用python写网络爬虫:3.urllib库进一步的使用方法

文章目录 异常处理URLErrorHTTPError设置超时时间 链接的解析、构造、合并urlparse方法urlsplit方法urljoin方法urlencode方法parse_qs方法quote方法 Robots 协议Robots 协议的结构解析协议 参考书籍 在上一篇文章&#xff1a;用python写网络爬虫&#xff1a;2.urllib库的基本用…