前言
多线程调用OpenFeign,线程中RequestAttributes丢失,导致请求异常
一、配置openfeign拦截器
添加token等相关信息,其他服务可进行验证
/**
* 描述: feign调用Request配置
*
* @author Mr.Yxd
*/
@Slf4j
public class CommonFeignConfig implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
log.error("异步线程调用-RequestAttributes丢失");
return;
}
//添加token
requestTemplate.header("access_token",attributes.getRequest().getHeader("access_token"));
requestTemplate.header("Com-Tk", "sdd");
requestTemplate.header("Com-Uid", "asset");
}
二、多线程调用问题
很多时候我们使用openfeign进行远程调用的时候,不需要等待返回,这个时候需要使用多线程异步调用,调用debug发现线程中,RequestAttributes丢失,深入发现原因:
- HttpServletRequest 大家应该都不陌生,一次 API 请求中,所有客户端的请求都被封装成一个 HttpServletRequest 对象里。这个对象在 API 请求时创建,响应完成后销毁,作为 Request 作用域的容器。
- 容器中投放和获取变量的方法,则可以用 HttpServletRequest 对象的 setAttribute/getAttribute 方法来实现
- 使用相关的工具类 RequestContextHolder 等,获取对象中Attribute,而RequestContextHolder 是基于 ThreadLocal 实现的,基于本地线程提供了Getter/Setter方法,但如果跨线程则丢失变量值
# 三、解决方案
在父线程创建子线程时将父线程当前存在的本地线程变量拷贝到子线程的本地线程变量中
//线程池初始化
TeadPool ins = TeadPool.getIns();
//获取主线程中的对象中的值
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ins.submit(() -> {
//植入子线程
RequestContextHolder.setRequestAttributes(requestAttributes);
//远程调用
feignService.send();
});