正文
@Override
public
void
afterCompletion
(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception arg3)
throws
Exception {
}
@Override
public
void
postHandle
(HttpServletRequest request,
HttpServletResponse response, Object handler, ModelAndView arg3)
throws
Exception {
}
@Override
public
boolean
preHandle
(HttpServletRequest request, HttpServletResponse response, Object handler)
throws
Exception
{
String traceId = request.getHeader(TRACE_ID);
if
(StringUtils.isEmpty(traceId)) {
MDC.put(TRACE_ID, UUID.randomUUID().toString());
}
else
{
MDC.put(TRACE_ID, traceId);
}
return
true
;
}
}
3)配置拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Resource
private LogInterceptor logInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor).addPathPatterns("/**");
}
}
4.3 traceId 如何在服务间传递
?
封装 HTTP 工具类,把 traceId 加入头中,带到下一个服务。
@Slf4j
public class HttpUtils {
public static String get(String url) throws URISyntaxException {
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, String> headers = new HttpHeaders();
headers.add("traceId", MDC.get("traceId"));
URI uri = new URI(url);
RequestEntity> requestEntity = new RequestEntity<>(headers, HttpMethod.GET, uri);
ResponseEntity exchange = restTemplate.exchange(requestEntity, String.class);
if (exchange.getStatusCode().equals(HttpStatus.OK)) {
log.info("send http request success");
}
return exchange.getBody();
}
}
4.4 traceId 如何在多线程中传递?
Spring 项目也使用到了很多线程池,比如 @Async 异步调用,Zookeeper 线程池、 Kafka 线程池等。不管是哪种线程池都大都支持传入指定的线程池实现,
拿
@Async
举例:
原理为:
MDC 底层使用
Thread
Local
来实现,那根据
Thread
Local
的特点,它是可以让我们在同一个线程中共享数据的,但是往往我们在业务方法中,会开启多线程来执行程序,这样的话 MDC 就无法传递到其他子线程了。这时,我们需要使用额外的方法来传递存在
Thread
Local
里的值。
MDC 提供了一个叫 getCopyOfContextMap 的方法,很显然,该方法就是把当前线程
Thread
Local
绑定的Map获取出来,之后就是把该 Map 绑定到子线程中的ThreadLocal 中了。
改造 Spring 的异步线程池,包装提交的任务。
@Slf4j
@Component
public class TraceAsyncConfigurer implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(8);
executor.setMaxPoolSize(16);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("async-pool-");
executor.setTaskDecorator(new MdcTaskDecorator());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();