openFeign 异步 调用丢失上下文怎么破?

简介: openFeign 异步 调用丢失上下文怎么破?

最近有读者问了这样一个问题:陈哥,openFeign异步调用总是失败触发Sentinel的降级,同步调用就没问题?

他还给我晒了一下代码,大致如下:

CompletableFuture<T> future1 = CompletableFuture.supplyAsync(() -> {
 //openfeign的调用
 return feign.remoteCall();
},executor);
CompletableFuture<T> future2 = CompletableFuture.supplyAsync(() -> {
 //openfeign的调用
 return feign.remoteCall();
},executor);
CompletableFuture.allOf(future1,future2).join();
.....

这种情况你遇到过吗?

如何解决?

这个算是常见问题了:feign的调用导致上下文丢失;前面有一篇文章说过这种问题:实战!openFeign如何实现全链路JWT令牌信息不丢失?

在集成OAuth2的时候如果做任何设置会丢失令牌信息,当时我们的解决方案是新建一个拦截器,如下:

@Component
@Slf4j
public class FeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        HttpServletRequest httpServletRequest = RequestContextUtils.getRequest();
        Map<String, String> headers = getHeaders(httpServletRequest);
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            template.header(entry.getKey(), entry.getValue());
        }
    }
    /**
     * 获取原请求头
     */
    private Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> map = new LinkedHashMap<>();
        Enumeration<String> enumeration = request.getHeaderNames();
        if (enumeration != null) {
            while (enumeration.hasMoreElements()) {
                String key = enumeration.nextElement();
                String value = request.getHeader(key);
                if (StrUtil.equals(OAuthConstant.TOKEN_NAME,key)){
                    map.put(key, value);
                    break;
                }
            }
        }
        return map;
    }
}

上述代码根本逻辑就是将请求头中Token信息放入RequestTemplate的头中。

注意:这里取出请求头中信息用的是RequestContextHolder

看到这里是不是明白了,RequestContextHolder中是将请求信息放入ThreadLocal中的,只能取到同一个线程的数据。

因此要解决异步调用的问题,只需要在发起远程调用之前给异步线程添加上主线程的上下文信息,此时最上方调用失效的代码变成如下:

//获取主线程的请求信息
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
CompletableFuture<T> future1 = CompletableFuture.supplyAsync(() -> {
   //将主线程的请求信息设置到异步线程中,否则会丢失请求上下文,导致调用失败
 RequestContextHolder.setRequestAttributes(attributes);
 //openfeign的调用
 return feign.remoteCall();
},executor);
CompletableFuture<T> future2 = CompletableFuture.supplyAsync(() -> {
   //将主线程的请求信息设置到异步线程中,否则会丢失请求上下文,导致调用失败
 RequestContextHolder.setRequestAttributes(attributes);
    //openfeign的调用
 return feign.remoteCall();
},executor);
CompletableFuture.allOf(future1,future2).join();
.....
相关文章
|
6月前
|
设计模式 Java Spring
【Spring源码】WebSocket做推送动作的底层实例是谁
我们都知道WebSocket可以主动推送消息给用户,那做推送动作的底层实例究竟是谁?我们先整体看下整个模块的组织机构。可以看到handleMessage方法定义了每个消息格式采用不同的消息处理方法,而这些方法该类并**没有实现**,而是留给了子类去实现。
【Spring源码】WebSocket做推送动作的底层实例是谁
|
6月前
|
Java Android开发
Android系统 获取用户最后操作时间回调实现和原理分析
Android系统 获取用户最后操作时间回调实现和原理分析
189 0
|
1月前
|
自然语言处理 JavaScript Java
Spring 实现 3 种异步流式接口,干掉接口超时烦恼
本文介绍了处理耗时接口的几种异步流式技术,包括 `ResponseBodyEmitter`、`SseEmitter` 和 `StreamingResponseBody`。这些工具可在执行耗时操作时不断向客户端响应处理结果,提升用户体验和系统性能。`ResponseBodyEmitter` 适用于动态生成内容场景,如文件上传进度;`SseEmitter` 用于实时消息推送,如状态更新;`StreamingResponseBody` 则适合大数据量传输,避免内存溢出。文中提供了具体示例和 GitHub 地址,帮助读者更好地理解和应用这些技术。
203 0
|
6月前
|
消息中间件 Kafka 数据处理
了解Kafka位移自动提交的秘密:避免常见陷阱的方法
了解Kafka位移自动提交的秘密:避免常见陷阱的方法
347 1
解决Feign远程调用参数里面内容丢失的问题
解决Feign远程调用参数里面内容丢失的问题
443 0
|
缓存 Java 数据中心
Hystrix执行时内部原理
Hystrix执行时内部原理
52 0
|
消息中间件 Java 数据挖掘
异步响应的应用详谈
在传统的同步响应方式中,当一个请求发送到服务器时,服务器会立即进行处理,并在处理完成后返回结果给客户端。而在异步响应中,服务器在接收到请求后,不会立即进行处理,而是将请求放入一个队列中,然后继续处理其他请求。当请求完成处理后,服务器会通过回调函数或消息通知的方式将结果返回给客户端。
199 0
|
Java Spring
spring如何保证事件顺序发送
spring如何保证事件顺序发送
|
Java Spring
一不小心,你就掉进了Spring延迟初始化的坑!
由于 spring bean 的默认作用域是:singleton。所以在启动的时候 bean 会被初始化,如果被标记了@Lazy,会延迟初始化,但是如果被非懒加载的 Bean 注入了,@Lazy会失效。
|
设计模式 缓存 安全
【Hystrix技术指南】(6)请求合并机制原理分析
【Hystrix技术指南】(6)请求合并机制原理分析
199 0
【Hystrix技术指南】(6)请求合并机制原理分析