springboot~openfeign開啟熔斷之后MDC為null的(de)解決
上一篇說了關于MDC跨線程為null的理解,而本講主要說一下,如何去解決它,事實上,Hystrix為我們留了這個口,我們只需要繼承HystrixConcurrencyStrategy,然后重寫wrapCallable方法,再把這個重(zhong)寫的對象注冊(ce)到Hystrix里就(jiu)可(ke)以(yi)了,跨線程(cheng)共享數據(ju),可(ke)以(yi)使用阿(a)里的 transmittable-thread-local組件(jian),如果只是共離MDC的話,可(ke)以(yi)自己寫個組件(jian)就(jiu)行。
一 ThreadMdcUtil用來同步MDC對象
public class ThreadMdcUtil {
public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) {
return () -> {
if (context == null) {
MDC.clear();
}
else {
MDC.setContextMap(context);
}
try {
return callable.call();
}
finally {
MDC.clear();
}
};
}
public static Runnable wrap(final Runnable runnable, final Map<String, String> context) {
return () -> {
if (context == null) {
MDC.clear();
}
else {
MDC.setContextMap(context);
}
try {
runnable.run();
}
finally {
MDC.clear();
}
};
}
}
重寫HystrixConcurrencyStrategy,將主線程的MDC傳入Hystrix建立的新線程
/**
* 線程上下文傳遞,hystrix的相關實現有興趣可以看源碼, hystrix提供了這個口子可以處理線程間傳值問題,這里不做過多贅述
*/
public class RequestContextHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
@Override
public <T> Callable<T> wrapCallable(final Callable<T> callable) {
// 使用阿里的 TtlCallable 重新包一層,解決線程間數據傳遞問題
// return TtlCallable.get(callable);
// 使用自定義的包裝對象,將當前mdc復制到Hystrix新線程中
return ThreadMdcUtil.wrap(callable, MDC.getCopyOfContextMap());
}
}
注冊我們的RequestContextHystrixConcurrencyStrategy策略到Hystrix
@Configuration
@Slf4j
public class HystrixCircuitBreakerConfiguration {
@PostConstruct
public void init() {
HystrixPlugins.getInstance().registerConcurrencyStrategy(
new RequestContextHystrixConcurrencyStrategy());
}
}
運行結果,使用openFeign時,已經共享了traceId這個數據值
