Seata源码(十七)XID传递


铿然架构 | 作者 / 铿然一叶 这是 铿然架构 的第 107 篇原创文章


1. XID作用

全局事务处理过程中,XID将一次业务请求涉及的所有微服务的数据库事务关联起来,XID也用于全局session的管理。

也因为如此,XID需要在多个微服务之间传递,给微服务内的RM和TM使用。

2.源码

源码来自:spring-cloud-starter-alibaba-seata

序号 类型
groupId com.alibaba.cloud
artifactId spring-cloud-alibaba-starters
module spring-cloud-starter-alibaba-seata

2.1 类结构和核心逻辑

XID传递的类结构如下:

XID传递的基本逻辑如下:

● 客户端将xid放入http请求的header属性"TX_XID"中,服务端收到HTTP请求后,从此属性获取。

● Restful请求和Feign请求都有各自的拦截器来填充xid到header属性中,对应上图分别是:Restful-SeataRestTemplateInterceptor;Feign-SeataFeignRequestInterceptor

● 服务端通过拦截器SeataHandlerInterceptor获取xid取值后,bind到线程变量RootContext中,使用时从此线程变量中获取。

2.2 客户端Restful拦截器

SeataRestTemplateInterceptor.java

java 复制代码
	public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes,
			ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
		HttpRequestWrapper requestWrapper = new HttpRequestWrapper(httpRequest);

		String xid = RootContext.getXID();

		if (StringUtils.hasLength(xid)) {
			requestWrapper.getHeaders().add(RootContext.KEY_XID, xid);
		}
		return clientHttpRequestExecution.execute(requestWrapper, bytes);
	}

2.3 客户端Feign拦截器

SeataFeignRequestInterceptor.java

java 复制代码
	public void apply(RequestTemplate template) {
		String xid = RootContext.getXID();
		if (!StringUtils.hasLength(xid)) {
			return;
		}

		List<String> seataXid = new ArrayList<>();
		seataXid.add(xid);
		template.header(RootContext.KEY_XID, xid);
	}

2.4 服务端拦截器

SeataHandlerInterceptor.java

java 复制代码
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
			Object handler) {
		String xid = RootContext.getXID();
		String rpcXid = request.getHeader(RootContext.KEY_XID);
		if (log.isDebugEnabled()) {
			log.debug("xid in RootContext {} xid in RpcContext {}", xid, rpcXid);
		}

		if (StringUtils.isBlank(xid) && rpcXid != null) {
			RootContext.bind(rpcXid);
			if (log.isDebugEnabled()) {
				log.debug("bind {} to RootContext", rpcXid);
			}
		}

		return true;
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
			Object handler, Exception e) {
		if (StringUtils.isNotBlank(RootContext.getXID())) {
			String rpcXid = request.getHeader(RootContext.KEY_XID);

			if (StringUtils.isEmpty(rpcXid)) {
				return;
			}

			String unbindXid = RootContext.unbind();
			if (log.isDebugEnabled()) {
				log.debug("unbind {} from RootContext", unbindXid);
			}
			if (!rpcXid.equalsIgnoreCase(unbindXid)) {
				log.warn("xid in change during RPC from {} to {}", rpcXid, unbindXid);
				if (unbindXid != null) {
					RootContext.bind(unbindXid);
					log.warn("bind {} back to RootContext", unbindXid);
				}
			}
		}
	}

其他阅读:

萌新快速成长之路
如何编写软件设计文档
JAVA编程思想(一)通过依赖注入增加扩展性
JAVA编程思想(二)如何面向接口编程
JAVA编程思想(三)去掉别扭的if,自注册策略模式优雅满足开闭原则
JAVA编程思想(四)Builder模式经典范式以及和工厂模式如何选?
Java编程思想(七)使用组合和继承的场景
JAVA基础(一)简单、透彻理解内部类和静态内部类
JAVA基础(二)内存优化-使用Java引用做缓存
JAVA基础(三)ClassLoader实现热加载
JAVA基础(四)枚举(enum)和常量定义,工厂类使用对比
JAVA基础(五)函数式接口-复用,解耦之利刃\

相关推荐
吴声子夜歌12 小时前
ApacheCommons——commons-pool2(高性能通用对象池框架)
java·开发语言·apache
xcl092517 小时前
幼儿托育系统开发实战:从需求分析到上线全流程指南
java·大数据·需求分析
吴声子夜歌17 小时前
ApacheCommons——commons-cli(命令行参数解析)
java·开发语言·apache
小小猪的春天17 小时前
Java 手写第一个 MCP Server:Spring AI MCP 半小时跑通
java·人工智能·spring boot·ai编程
find1star17 小时前
LeetCode 141:环形链表
java·算法·leetcode·链表
今天AI了吗18 小时前
DeepSeek Harness 深度解析:从评测架构到实战落地
java·网络·数据库·人工智能·架构·java-ee
许彰午18 小时前
27-AuthService登录链路
java·低代码·架构
泡海椒19 小时前
JQuick-Curl 性能分析:并发场景下的性能表现与调优,第三方接口调用不只要快写也要稳跑
java·开发语言·okhttp
Rain的Java大神之路20 小时前
JavaWeb开发如何解决跨域问题
java·前端·后端·nginx·web安全·面试·运维开发
自动化监测Learner20 小时前
Navicat Premium 17 中文版安装教程(2026最新版)
java·linux·数据库