项目代码:
https://gitee.com/gangye/springboot_mutiDemos/releases/v1.1
案例:在springboot_demoB应用使用RestTemplate调动springboot_demoA的服务,将B服务的traceId塞入到A的traceId中
成功将traceId塞入,下面直接上代码,相应的代码已上传资源,在之前的v1.0上增加了RestTemplate和okhttp请求方式的拦截做MDC的traceId日志处理
https://gitee.com/gangye/springboot_mutiDemos/releases/v1.1
此处我在RestTemplate中使用了okHttp的方式去连接请求,因为okHttp请求可以设置连接池,自定义超时时间,服务代理等功能,所以我使用了okhttp的方式,没有使用默认的RestTemplate,当然若使用原生的RestTemplate,我也写了相应的拦截功能作为参考(亲测也可实现功能)
在application.yml中增加okHttp的连接配置
编写RestTemplateConfig类,创建RestTemplate的Bean,和配置okHttpClient的Bean,后期若使用okHttp请求连接可以直接使用okHttpClient的Bean
import com.csrcb.interceptor.OkHttpLoggerInterceptor;
import com.csrcb.interceptor.RestTemplateInterator;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
/**
* @Classname RestTemplateConfig
* @Description RestTemplate配置,内部使用okhttp请求连接,使用okhttp的请求连接池,超时等特性
* @Date 2021/8/18 15:02
* @Created by gangye
*/
@Configuration
public class RestTemplateConfig {
@Value("${ok.http.connect-timeout}")
private Integer connectTimeout;
@Value("${ok.http.read-timeout}")
private Integer readTimeout;
@Value("${ok.http.write-timeout}")
private Integer writeTimeout;
@Value("${ok.http.max-idle-connections}")
private Integer maxIdleConnections;
@Value("${ok.http.keep-alive-duration}")
private Long keepAliveDuration;
@Bean
public RestTemplate okHttpRestTemplate(){
ClientHttpRequestFactory factory = okHttpClientRequestFactory();
RestTemplate restTemplate = new RestTemplate(factory);
// 可以添加消息转换
//restTemplate.setMessageConverters(...);
// 可以增加拦截器
// restTemplate.setInterceptors(Arrays.asList(new RestTemplateInterator()));
return restTemplate;
/*
//此情形用于使用纯RestTemplate的情形下使用拦截器,传递traceId等日志链路
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(Arrays.asList(new RestTemplateInterator()));
return restTemplate;
*/
}
@Bean
public ClientHttpRequestFactory okHttpClientRequestFactory(){
//使用自定义的okHttpClient
return new OkHttp3ClientHttpRequestFactory(okHttpClient());
}
@Bean
public OkHttpClient okHttpClient(){
return new OkHttpClient.Builder()
.connectTimeout(connectTimeout,TimeUnit.SECONDS)
.readTimeout(readTimeout, TimeUnit.SECONDS)
.writeTimeout(writeTimeout,TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(maxIdleConnections,keepAliveDuration,TimeUnit.SECONDS))
// 设置代理
// .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8888)))
// 拦截器
.addInterceptor(new OkHttpLoggerInterceptor())
.build();
}
}
编写okHttp的拦截器OkHttpLoggerInterceptor,此时需要日志打印的也可以在拦截器中编写请求的url,请求报文以及返回报文日志
import com.csrcb.constants.MyConstant;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.Buffer;
import okio.BufferedSource;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.http.HttpStatus;
import java.io.IOException;
import java.util.UUID;
/**
* @Classname OkHttpLoggerInterceptor
* @Description okhttp请求的拦截器,将traceId及parentSpanId塞入
* @Date 2021/8/18 17:24
* @Created by gangye
*/
@Slf4j
public class OkHttpLoggerInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
//目前默认使用的是post请求,且格式是utf8,使用的是application/json
Request request = chain.request();
//copy all headers to newheaders
Headers.Builder headers = request.headers().newBuilder();
//add traceid | spanid | parentspanid to headers
if (StringUtils.isNotBlank(MDC.get(MyConstant.TRACE_ID_MDC_FIELD))){
headers.add(MyConstant.TRACE_ID_HTTP_FIELD, MDC.get(MyConstant.TRACE_ID_MDC_FIELD));//设置X-B3-TraceId
}
if (StringUtils.isNotBlank(MyConstant.SPAN_ID_MDC_FIELD)){
headers.add(MyConstant.PARENT_SPAN_ID_HTTP_FIELD,MDC.get(MyConstant.SPAN_ID_MDC_FIELD));
}
String spanIdNew = UUID.randomUUID().toString().replace("-","").substring(0,16);
headers.add(MyConstant.SPAN_ID_HTTP_FIELD, spanIdNew);//设置X-B3-SpanId供外部使用
//rebuild a new request
request = request.newBuilder().headers(headers.build()).build();
Buffer buffer = new Buffer();
request.body().writeTo(buffer);
String requestBody = buffer.readUtf8();
String requestUrl = request.url().toString();
String[] url = requestUrl.split("/");
log.info("[Request Addr]: " + request.url());
log.info("[Service Name]: " + url[url.length - 1]+ "; [Request Body]: " + requestBody);
Response response = chain.proceed(request);
BufferedSource source = response.body().source();
source.request(Long.MAX_VALUE);
buffer = source.buffer();
String responseBody = buffer.readUtf8();
log.info("[Response Status Code]: " + response.code() + "; [Resonse Status Text]: " + HttpStatus.valueOf(response.code()).name());
log.info("[Service Name]: " + url[url.length - 1]+ "; [Response Body]: " + responseBody);
return response.newBuilder().body(ResponseBody.create(response.body().contentType(), responseBody)).build();
}
}
至于如使用原生的RestTemplate去请求,RestTemplate也可以定义自己的拦截器
代码如下供参考,不过个人任然推荐在RestTemplat中使用okHttp
import com.csrcb.constants.MyConstant;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import java.io.IOException;
import java.util.UUID;
/**
* @Classname RestTemplateInterator
* @Description restTemplate请求的拦截器,将traceId及parentSpanId塞入
* @Date 2021/8/19 9:56
* @Created by gangye
*/
public class RestTemplateInterator implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
String traceId = MDC.get(MyConstant.TRACE_ID_HTTP_FIELD);
if (StringUtils.isNotBlank(traceId)) {
httpRequest.getHeaders().add(MyConstant.TRACE_ID_HTTP_FIELD, traceId);
}
String spanIdNew = UUID.randomUUID().toString().replace("-","").substring(0,16);
httpRequest.getHeaders().add(MyConstant.SPAN_ID_HTTP_FIELD, spanIdNew);//设置X-B3-SpanId供外部使用
if (StringUtils.isNotBlank(MDC.get(MyConstant.SPAN_ID_MDC_FIELD))){
httpRequest.getHeaders().add(MyConstant.PARENT_SPAN_ID_HTTP_FIELD,MDC.get(MyConstant.SPAN_ID_MDC_FIELD));
}
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/12285.html