Java中请求生成唯一追溯TraceId

Java中请求生成唯一追溯TraceId

一:背景

因为是微服务架构,平常日志太多,看日志不太好查,所以想要从一整个链路当中获取一个唯一标识,比较好定位问题,

原理就是从gateway网关将标识传递到下游,下游服务拿到这个标识,响应结束后将traceId反向写入响应体中

二:具体实现

例如我现在有3个微服务,gateway,center-service,注册中心;一个接口完整的请求链路是从gateway路由到center-service中。

1、Gateway

网关处理请求唯一标识

package com.wondertek.gateway.traceId;import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.List;
import java.util.UUID;@Component
@Slf4j
public class TraceIdResponseFilter implements GlobalFilter, Ordered {private static final String TRACE_ID_HEADER = "X-Trace-Id";@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 在请求前确保traceId存在List<String> existingTraceIds = exchange.getRequest().getHeaders().get(TRACE_ID_HEADER);String traceId = existingTraceIds != null ? existingTraceIds.get(0) : UUID.randomUUID().toString().replaceAll("-","");log.info("网关传递到下游服务的traceId值为:{}", traceId);exchange.getRequest().mutate().header(TRACE_ID_HEADER, traceId).build();return chain.filter(exchange).then(Mono.fromRunnable(() -> {// 在响应后添加traceId到响应头ServerHttpResponse response = exchange.getResponse();response.getHeaders().add(TRACE_ID_HEADER, traceId);}));}@Overridepublic int getOrder() {// 响应后执行return Ordered.LOWEST_PRECEDENCE;}
}

2、center-service

得将此拦截器注册到您的MVC配置中

package com.wondertek.web.traceId;import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
@Slf4j
public class TraceIdInterceptor implements HandlerInterceptor {private static final String TRACE_ID_HEADER = "X-Trace-Id";/*** 这个方法在请求处理之前被调用。在这里,它试图从请求头中获取名为 X-Trace-Id 的值,这通常是一个用于追踪请求在不同微服务之间流转的唯一标识符。* 如果这个标识符存在,它会被保存在请求的属性中,这样在后续的处理流程中可以继续访问和使用这个 traceId。* @param request* @param response* @param handler* @return*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 提取请求头中的traceIdString traceId = request.getHeader(TRACE_ID_HEADER);// 如果traceId存在,则将其存储到请求中供后续使用if (traceId != null) {request.setAttribute(TRACE_ID_HEADER, traceId);}return true;}/*** 这个方法在请求处理之后被调用,但在视图渲染之前执行。* 在这里,它从请求属性中获取之前存储的 traceId,然后将这个 traceId 设置在响应头中。* 这样做保证了,如果请求中包含了 traceId,那么这个 traceId 将会随着响应返回给发起请求的客户端。* @param request* @param response* @param handler* @param modelAndView*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {// 将traceId设置到响应头中,确保返回给调用者Object traceId = request.getAttribute(TRACE_ID_HEADER);if (traceId != null) {response.setHeader(TRACE_ID_HEADER, traceId.toString());}}// 其他方法根据需要实现/*** afterCompletion方法是Spring MVC的 HandlerInterceptor 接口中的一个回调函数,它在整个请求处理完毕后执行,也就是在视图渲染完毕且响应已经被发送给客户端之后。* 这个方法会在请求的最后阶段被调用,通常用于清理资源,记录日志,进行异常处理等操作。* 这个方法提供了四个参数:* HttpServletRequest:当前的请求对象。* HttpServletResponse:当前的响应对象。* Object:处理器(通常是一个控制器)。* Exception:执行处理器过程中抛出的异常。如果没有异常抛出则为null。*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {if (ex != null) {// 日志中记录异常信息log.error("请求处理发生错误,url:{}", ex,request.getServletPath());} else {// 日志中记录请求处理成功log.info("请求处理成功,url:{}",request.getServletPath());}// 这里还可以根据需要进行其他操作}}

将此拦截器注册到您的MVC配置中

package com.wondertek.web.traceId;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class TraceIdWebConfig implements WebMvcConfigurer {private final TraceIdInterceptor traceIdInterceptor;@Autowiredpublic TraceIdWebConfig(TraceIdInterceptor traceIdInterceptor) {this.traceIdInterceptor = traceIdInterceptor;}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(traceIdInterceptor);}
}

响应请求体中反写traceId

package com.wondertek.web.traceId;import com.wondertek.web.exception.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import org.springframework.web.bind.annotation.ControllerAdvice;import java.util.UUID;@ControllerAdvice
@Slf4j
public class TraceIdResponseBodyAdvice implements ResponseBodyAdvice<Object> {private static final String TRACE_ID_HEADER = "X-Trace-Id";@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {//如果只想处理返回类型为Result的控制器方法,您可以在supports方法中做出相应的判断:// return returnType.getParameterType().equals(Result.class);// 可以进一步细化条件,只处理Result类型的响应//这个supports方法的实现总是返回true,这意味着无论返回类型或者转换器类型是什么,当前的ResponseBodyAdvice实现都将被用于所有的响应。return true;}/*** 此代码段是ResponseBodyAdvice接口中beforeBodyWrite方法的一个具体实现。此方法允许您在响应体被发送给客户端前对其进行修改。* @param body* @param returnType* @param selectedContentType* @param selectedConverterType* @param request* @param response* @return*/@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 从请求头中提取traceIdString traceId = request.getHeaders().getFirst(TRACE_ID_HEADER);if (body instanceof Result) {Result<?> result = (Result<?>) body;if (traceId != null) {log.info("下游服务接收到的traceId值为:{}", traceId);result.setTraceId(traceId);} else {// 如果服务从请求头中获取不到traceId,生成一个新的traceId = UUID.randomUUID().toString().replaceAll("-", "");//log.info("下游服务生成的traceId值为:{}", traceId);result.setTraceId(traceId);}}return body;}
}

Result为自己定义的全局返回对象,其中要加入traceId

image-20240105101009657

image-20240105101208037

三:实现效果

image-20240105100450724image-20240105100530070

image-20240105100556152

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/597987.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[论文笔记] Megtron_LM 0、报错:vscode调试无法传进去参数 launch.json文件获取args参数

解决方法&#xff1a; 配置好launch.json文件后&#xff0c;应该点运行和调试里面的运行按钮。而不是直接点文件右上角的debug。 可以看到terminal中&#xff0c;如果没有正常加载launch.json&#xff0c;则参数中没有args的参数。 如果正常加载&#xff0c;可以看到args的很多…

Java中的IO与NIO篇----第四篇

系列文章目录 文章目录 系列文章目录前言一、NIO 的非阻塞二、Channel三、Buffer四、Selector前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 一、NIO 的非阻塞 I…

C++ OpenGL 3D GameTutorial 1:Making the window with win32 API学习笔记

视频地址https://www.youtube.com/watch?vjHcz22MDPeE&listPLv8DnRaQOs5-MR-zbP1QUdq5FL0FWqVzg 一、入口函数 首先看入口函数main代码&#xff1a; #include<OGL3D/Game/OGame.h>int main() {OGame game;game.Run();return 0; } 这里交代个关于C语法的问题&#x…

释放创造力:可视化页面渲染引擎在低代码开发平台的应用

本文由葡萄城技术团队发布。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 什么是页面渲染引擎? 页面渲染引擎是低代码开发平台的核心组件之一&#xff0c;它负责将开发者设计的页面布局和用户…

计算机网络学习笔记(5)——运输层

本文继续整理计算机网络体系架构知识内容。今日主讲——运输层。 网络层只把分组发送到目的主机&#xff0c;但是真正通信的并不是主机而是主机中的进程。 运输层提供了应用进程间的逻辑通信。运输层向高层用户屏蔽了下面网络层的核心细节&#xff0c;使应用程序看 见的好像在两…

python+selenium爬虫笔记

本文只是做例子&#xff0c;具体网站路径麻烦你们换下&#xff0c;还有xpath路径也换下 一、安装所需要的组件&#xff08;此处采用谷歌&#xff09; 1、安装驱动 查看你的浏览器版本&#xff0c;去安装对应的版本 下载驱动 下载驱动路径 之前版本的 输入这个路径下载下来解压…

TikTok革新游戏规则:解读短视频对社交媒体的影响

在社交媒体的巨浪中&#xff0c;TikTok以其独特的短视频形式和强大的创意社区&#xff0c;重新定义了游戏规则。这个以15秒视频为核心的平台&#xff0c;不仅让用户获得了表达自我的新方式&#xff0c;更深刻地影响了社交媒体的演进。本文将深入解读TikTok对社交媒体的影响&…

支持下载和阅读的漫画管理工具Teemii

什么是 Teemii &#xff1f; Teemii 是一款专为狂热漫画读者设计的精简 Web 应用程序。它为阅读和管理漫画集提供了一个简单而高效的平台。主要功能包括跨平台访问、浏览器内阅读、强大的元数据聚合器以及馆藏自动更新。Teemii 是专为那些寻求更加个性化和自主的方法来管理漫画…

[Kubernetes]4. 借助腾讯云TKE快速创建Pod、Deployment、Service部署k8s项目

前面讲解了通过命令行方式来部署k8s项目,下面来讲讲通过腾讯云TKE来快速创建Pod、Deployment、Service部署k8s项目,云平台搭建Kubernetes可参考[Kubernetes]1.Kubernetes(K8S)介绍,基于腾讯云的K8S环境搭建集群以及裸机搭建K8S集群 一.通过腾讯云TKE创建集群 1.创建集群 参考上…

Kibana 自定义索引连接器告警

一、 创建索引 PUT ipu-cbs-warning-info{"settings" : {"number_of_shards" : 1},"mappings" : {"properties" : {"timestamp": {"type": "date"},"rule_id" : { "type" : "…

经纬度的作用

当我们在手机上使用导航软件或者在网上查找地址时&#xff0c;经常会发现一个选项&#xff0c;就是显示当前位置的经纬度。那么&#xff0c;什么是经纬度&#xff0c;它有什么作用呢&#xff1f; 经纬度是用来确定地球上任何一个点位置的坐标系统。它由两个数值组成&#xff0…

【完整流程】实现STM32+ESP8266+MQTT+阿里云+APP——【第二节-编写STM32程序初步实现ESP8266上云发布订阅消息】

&#x1f31f;博主领域&#xff1a;嵌入式领域&人工智能&软件开发 前言&#xff1a;本节实现&#xff0c;硬件连接STM32与ESP8266&#xff0c;编写STM32程序通过at命令方式实现STM32ESP8266与阿里云物联网平台发布订阅消息&#xff0c;本节最终实现初步的发布订阅消息…

2024年AMC8竞赛真题模拟比赛做一做(25题40分钟,含答案)

这两天陆续有家长朋友问我是否有2024年AMC8比赛的模拟题&#xff0c;有一些家长是想通过做模拟题来检查孩子的学习和备考情况&#xff0c;另外一些家长式准备“谋定而后动”&#xff0c;想让孩子先做一做&#xff0c;看看难不难&#xff0c;如果还可以再报名2024年的AMC8竞赛。…

芯课堂 | LVG免费开源GUI图形库

概述 本文介绍目前LVGL的应用小知识&#xff0c;希望对采用MCU设计UI界面的用户有所启发&#xff0c;开发出界面更友好的消费品或者工业产品&#xff0c;造福大众。 01.LVGL系统架构 LVGL系统框架 应用程序创建GUI并处理特定任务的应用程序。 LVGL本身是一个图形库。我们的…

Python Selenium如何下载网页中的图片到本地?(Base64编码的图片下载)

前言&#xff1a; 在网页上&#xff0c;图片有时会以Base64编码的形式嵌入在HTML中&#xff0c;而不是作为单独的文件提供。这种方式的优点是可以减少HTTP请求的数量&#xff0c;因为图片数据直接包含在HTML中&#xff0c;不需要额外的请求来获取图片文件。这对于小图片…

【TC3xx芯片】TC3xx芯片的GTM模块详解

目录 前言 正文 1.GTM模块功能概述 1.1 GTM具体功能 1.2 GTM架构 2. GTM模块输入时钟 2.1.fGTM的值怎么计算 3. CMU 3.1 CMU功能 3.2 CMU时钟的计算 3..2.1 CLS0_CLK怎么计算 3.2.1 GTM Global Clock时钟计算 3.2.2 分频时钟的计算 4. CCM 4.1 CCM功能 4.2 CCM…

SpringMVC-视图

SpringMVC中的视图实现了View接口&#xff0c;作用是渲染数据&#xff0c;将Model中的数据展示给用户。render是渲染方法&#xff0c;可以看到渲染的视图是一个View类型的对象。 SpringMVC视图的种类有很多&#xff0c;默认有转发视图和重定向视图。 如果配置了Thymeleaf视图解…

使用Docker方式安装Artifactory

1、安装前环境准备 首先要关闭防火墙&#xff0c;关闭Selinux&#xff0c;准备好安装好的docker。以下安装版本&#xff1a;7.19.10 ##关闭防火墙&#xff0c;并设置开机自关闭 systemctl stop firewalld.service systemctl disable firewalld.service ##查看防火墙状态 sy…

SpringCloud Alibaba之Nacos配置中心配置详解

目录 Nacos配置中心数据模型Nacos配置文件加载Nacos配置 Nacos配置中心数据模型 Nacos 数据模型 Key 由三元组唯一确定&#xff0c;三元组分别是Namespace、Group、DataId&#xff0c;Namespace默认是公共命名空间&#xff08;public&#xff09;&#xff0c;分组默认是 DEFAUL…

『年度总结』逐梦编程之始:我的2023学习回顾与展望

目录 前言 我与Python 我与C语言 第一篇正式博客&#xff1a; 第二篇正式博客&#xff08;扫雷&#xff09;&#xff1a; 指针学习笔记: C语言学习笔记&#xff1a; 我与数据结构&#xff1a; yuan 这篇博客&#xff0c;我将回顾2023年编程之旅的起点&#xff0c;同时展…