上一篇說了關於MDC跨線程為null的理解,而本講主要說一下,如何去解決它,事實上,Hystrix為我們留了這個口,我們只需要繼承HystrixConcurrencyStrategy,然後重寫wrapCallable方法,再把這個重寫的對象註冊到Hystrix里就可以了,跨線程共用數據,可以使用阿裡 ...
上一篇說了關於MDC跨線程為null的理解,而本講主要說一下,如何去解決它,事實上,Hystrix為我們留了這個口,我們只需要繼承HystrixConcurrencyStrategy,然後重寫wrapCallable
方法,再把這個重寫的對象註冊到Hystrix里就可以了,跨線程共用數據,可以使用阿裡的 transmittable-thread-local組件,如果只是共離MDC的話,可以自己寫個組件就行。
一 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這個數據值
作者:倉儲大叔,張占嶺,
榮譽:微軟MVP
QQ:853066980
支付寶掃一掃,為大叔打賞!