我们都知道,在hystrix默认情况下,采用线程池的熔断方式,每个openfeign都有自己的线程,而这使得它无法获取主线程上的变量;现在有个现实的问题就是,当前端登录后,把token经过gateway传到服务A,服务A再调用服务B时,B是无法收到请求头里的token信息的;一种不太好的解决方案就是使用信号量的方式。

使用ThreadLocal存储变量

public class NextHttpHeader {

static final InheritableThreadLocal> inheritableThreadLocal = new InheritableThreadLocal<>();

public static void set(String key, String val) {

if (inheritableThreadLocal.get() == null) {

inheritableThreadLocal.set(MapUtils.hashMapBuilder(8).put(key, val).build());

} else {

inheritableThreadLocal.get().put(key, val);

}

}

public static String get(String key) {

if (inheritableThreadLocal.get() == null) {

return null;

}

return inheritableThreadLocal.get().get(key);

}

public static Set get() {

if (inheritableThreadLocal.get() == null) {

return null;

}

return inheritableThreadLocal.get().keySet();

}

}

继承HystrixConcurrencyStrategy抽象类,实现自己的赋值逻辑

public class RequestContextHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {

public Callable wrapCallable(Callable callable) {

// 先包装一下要执行的任务,在这里把ThreadLocal的值取出来

return new ThreadLocalCallable(callable);

}

public static class ThreadLocalCallable implements Callable {

private Callable target;

private Map dic = new HashMap<>();

public ThreadLocalCallable(Callable target) {

this.target = target;

NextHttpHeader.get().forEach(o -> {

this.dic.put(o, NextHttpHeader.get(o));

});

}

@Override

public V call() throws Exception {

this.dic.keySet().forEach(o -> {

NextHttpHeader.set(o, this.dic.get(o));

});

return target.call();

}

}

}

注册

@Configuration

@Slf4j

public class HystrixCircuitBreakerConfiguration {

@PostConstruct

public void init() {

HystrixPlugins.getInstance().registerConcurrencyStrategy(new RequestContextHystrixConcurrencyStrategy());

}

}

发现openFeign请求时,将变量放到请求头

/**

* 基于openFeign的拦截器,处理需要向下游传递的信息.

*

* @author lind

* @date 2023/1/29 11:44

* @since 1.0.0

*/

@Configuration

public class FeignTraceIdInterceptor implements RequestInterceptor {

@Override

public void apply(RequestTemplate template) {

if (NextHttpHeader.get() != null) {

NextHttpHeader.get().forEach(o -> {

template.header(o, NextHttpHeader.get(o));

});

}

}

}

spring中的口子太多,太灵活,需要不断的去找那个最优雅,最正确的方法

好文阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。