Seata AT模式源码解析(一) ------ GlobalTransactionalInterceptor

  在pom.xml添加以下内容,本文基于以下版本源码进行分析。

    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-alibaba-seata</artifactId>
      <version>2.1.0.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>io.seata</groupId>
      <artifactId>seata-all</artifactId>
      <version>1.4.2</version>
    </dependency>

  直接看到spring-cloud-alibaba-seata-2.1.0.RELEASE.jar的spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.seata.rest.SeataRestTemplateAutoConfiguration,\
com.alibaba.cloud.seata.web.SeataHandlerInterceptorConfiguration,\
com.alibaba.cloud.seata.GlobalTransactionAutoConfiguration,\
com.alibaba.cloud.seata.feign.SeataFeignClientAutoConfiguration,\
com.alibaba.cloud.seata.feign.hystrix.SeataHystrixAutoConfiguration

  SeataRestTemplateAutoConfiguration用于支持restTemplate的远程调用,传递XID(全局事务id)

@Configuration
public class SeataRestTemplateAutoConfiguration {
   
   
	
	//SeataRestTemplateInterceptor交给Spring管理
	@Bean
	public SeataRestTemplateInterceptor seataRestTemplateInterceptor() {
   
   
		return new SeataRestTemplateInterceptor();
	}
	
	//依赖注入所有的RestTemplate
	@Autowired(required = false)
	private Collection<RestTemplate> restTemplates;
	
	//依赖注入拦截器
	@Autowired
	private SeataRestTemplateInterceptor seataRestTemplateInterceptor;

	@PostConstruct
	public void init() {
   
   
		if (this.restTemplates != null) {
   
   
			for (RestTemplate restTemplate : restTemplates) {
   
   
				List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>(
						restTemplate.getInterceptors());
				//添加了一个拦截器
				interceptors.add(this.seataRestTemplateInterceptor);
				restTemplate.setInterceptors(interceptors);
			}
		}
	}

}
public class SeataRestTemplateInterceptor implements ClientHttpRequestInterceptor {
   
   
	@Override
	public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes,
			ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
   
   
		HttpRequestWrapper requestWrapper = new HttpRequestWrapper(httpRequest);
		
		//获取XID(threadlocal)
		String xid = RootContext.getXID();

		if (!StringUtils.isEmpty(xid)) {
   
   
		    //如果有XID则设置到request的HttpHeaders中
			requestWrapper.getHeaders().add(RootContext.KEY_XID, xid);
		}
		
		return clientHttpRequestExecution.execute(requestWrapper, bytes);
	}
}

  SeataHandlerInterceptorConfiguration实现了WebMvcConfigurer接口,添加了Interceptor去接收请求携带过来的XID

public class SeataHandlerInterceptorConfiguration implements WebMvcConfigurer {
   
   

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
   
   
	    //所有请求都拦截
		registry.addInterceptor(new SeataHandlerInterceptor()).addPathPatterns("/**");
	}
}
public class SeataHandlerInterceptor implements HandlerInterceptor {
   
   

	private static final Logger log = LoggerFactory
			.getLogger(SeataHandlerInterceptor.class);
	
	//调用到业务代码前,绑定XID
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
			Object handler) {
   
   
		
		//获取当前的XID
		String xid = RootContext.getXID();
		//获取请求携带过来的XID
		String rpcXid = request.getHeader(RootContext.KEY_XID);
		if (log.isDebugEnabled()) {
   
   
			log.debug("xid in RootContext {} xid in RpcContext {}", xid, rpcXid);
		}
		
		//当前没有XID,且请求携带了XID
		if (xid == null && rpcXid != null) {
   
   
		    //将rpcXid绑定到threadlocal中,则自己为该全局事务中的一员
			RootContext.bind(rpcXid);
			if (log.isDebugEnabled()) {
   
   
				log.debug("bind {} to RootContext", rpcXid);
			}
		}
		return true;
	}
	
	//调用完成结果返回以后,解绑XID
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
			Object handler, Exception e) {
   
   
		//获取请求携带的XID
		String rpcXid = request.getHeader(RootContext.KEY_XID);
		
		if (StringUtils.isEmpty(rpcXid)) {
   
   
			return;
		}
		
		//从threadlocal中移除XID
		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);
			}
		}
	}
}

  GlobalTransactionAutoConfiguration主要实例化了GlobalTransactionScanner 这个bean

@Configuration
@EnableConfigurationProperties(SeataProperties.class)
public class GlobalTransactionAutoConfiguration {
   
   
	
	private final ApplicationContext applicationContext;

	private final SeataProperties seataProperties;

	public GlobalTransactionAutoConfiguration(ApplicationContext applicationContext,
			SeataProperties seataProperties) {
   
   
		this.applicationContext = applicationContext;
		this.seataProperties = seataProperties;
	}
	
	//实例化GlobalTransactionScanner
	@Bean
	public GlobalTransactionScanner globalTransactionScanner() {
   
   

		String applicationName = applicationContext.getEnvironment()
				.getProperty("spring.application.name");

		String txServiceGroup = seataProperties.getTxServiceGroup();

		if (StringUtils.isEmpty(txServiceGroup)) {
   
   
			txServiceGroup = applicationName + "-fescar-service-group";
			seataProperties.setTxServiceGroup(txServiceGroup);
		}
		
		return new GlobalTransactionScanner(applicationName, txServiceGroup);
	}
}

//获取spring.cloud.alibaba.seat.tx-service-group的属性
@ConfigurationProperties("spring.cloud.alibaba.seata")
public class SeataProperties {
   
   

	// todo support config Fescar server information

	/**
	 * Seata tx service group.default is ${spring.application.name}-fescar-service-group.
	 */
	private String txServiceGroup;

	public String getTxServiceGroup() {
   
   
		return txServiceGroup;
	}

	public void setTxServiceGroup(String txServiceGroup) {
   
   
		this.txServiceGroup = txServiceGroup;
	}

}

  SeataHystrixAutoConfiguration支持hytrix拦截器远程调用时的XID传递

@Configuration
@ConditionalOnClass(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值