事务参与方 - 969251639/study GitHub Wiki
从上图可以看到,事务发起方发起事务后,会传递事务组传递给参与方,下面以spring cloud为例
1. 发起方发送在头信息发送事务组
用springcloud其实很简单,不管用feign还是resttemplate都可以在springcloud发起http请求前通过拦截器设置头部信息
@ConditionalOnClass(Feign.class)
@Component
@Order
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
if (TracingContext.tracing().hasGroup()) {
requestTemplate.header(TracingConstants.HEADER_KEY_GROUP_ID, TracingContext.tracing().groupId());
requestTemplate.header(TracingConstants.HEADER_KEY_APP_MAP, TracingContext.tracing().appMapBase64String());
}
}
}
@ConditionalOnClass(RestTemplate.class)
@Component
@Order
public class RestTemplateRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
@NonNull
public ClientHttpResponse intercept(
@NonNull HttpRequest httpRequest, @NonNull byte[] bytes,
@NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
if (TracingContext.tracing().hasGroup()) {
httpRequest.getHeaders().add(TracingConstants.HEADER_KEY_GROUP_ID, TracingContext.tracing().groupId());
httpRequest.getHeaders().add(TracingConstants.HEADER_KEY_APP_MAP, TracingContext.tracing().appMapBase64String());
}
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
}
2. 参与方参与该事务组
参与方会从头部中获取事务组信息进行分布式参与。其实内部也是通过拦截器拦截在进入前将其设置到LCN事务的上下文中
@ConditionalOnClass(HandlerInterceptor.class)
@Component
public class TracingHandlerInterceptor implements com.codingapi.txlcn.tracing.http.spring.HandlerInterceptor, WebMvcConfigurer {
...
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String groupId = Optional.ofNullable(request.getHeader(TracingConstants.HEADER_KEY_GROUP_ID)).orElse("");
String appList = Optional.ofNullable(request.getHeader(TracingConstants.HEADER_KEY_APP_MAP)).orElse("");
TracingContext.tracing().init(Maps.newHashMap(TracingConstants.GROUP_ID, groupId, TracingConstants.APP_MAP, appList));//设置到事务上下文中
return true;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(this);
}
}
这样,在进入事务处理时就可以拿到这个组信息
@Component
@Slf4j
public class DTXLogicWeaver {
...
public Object runTransaction(DTXInfo dtxInfo, BusinessCallback business) throws Throwable {
...
DTXLocalContext dtxLocalContext = DTXLocalContext.getOrNew();
TxContext txContext;
if (globalContext.hasTxContext()) {//这里可以获取到事务组信息
// 有事务上下文的获取父上下文
txContext = globalContext.txContext();
dtxLocalContext.setInGroup(true);
log.debug("Unit[{}] used parent's TxContext[{}].", dtxInfo.getUnitId(), txContext.getGroupId());
} else {
// 没有的开启本地事务上下文
txContext = globalContext.startTx();
}
...
}
}