当前支持微服务框架有dubbo、openfeign、grpc,开发者如果使用其他的框架并且同时也遇到分布式事务场景,可以参考以下内容。
支持新的RPC框架只需解决事件上下文传递问题即可。 这里以我们openfeign的支持为例进行说明。
定义拦截器FeignInterceptor,实现openfeign调用的拦截。 代码如下:
public class FeignInterceptor implements RequestInterceptor {
private TransactionContextSerializer transactionContextSerializer = new TransactionContextSerializer();
@Override
public void apply(RequestTemplate requestTemplate) {
Annotation annotation = requestTemplate.methodMetadata().method().getAnnotation(EnableTcc.class);
if (annotation != null && TransactionContextHolder.getCurrentTransactionContext() != null) {
requestTemplate.header(TransactionContextConstants.TRANSACTION_CONTEXT,
Base64.getEncoder().encodeToString(transactionContextSerializer.serialize(TransactionContextHolder.getCurrentTransactionContext())));
}
return;
}
}
被拦截的FeignClient,以下代码来源于tcc-transaction-http-sample
@FeignClient(name = "capital", url = "http://localhost:8082/tcc-transaction-http-capital/")
public interface CapitalFeignClient {
@EnableTcc
@RequestMapping(value = "/tradeOrder/record", method = RequestMethod.POST)
@ResponseBody
String record(@RequestBody CapitalTradeOrderDto tradeOrderDto);
}
注意事项
1、ConfigurableCoordinatorAspect识别@EnableTcc,执行添加事件参与方,并保存分支事件上下文到TransactionContextHolder中
2、feign拦截器内部识别此注解才传递事件上下文,避免无效传递。
web服务端拦截,实现如下:
public class RequesterInterceptor implements HandlerInterceptor {
private TransactionContextSerializer transactionContextSerializer = new TransactionContextSerializer();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String transactionContext = request.getHeader(TransactionContextConstants.TRANSACTION_CONTEXT);
if (StringUtils.isNotEmpty(transactionContext)) {
TransactionContextHolder.setCurrentTransactionContext(transactionContextSerializer.deserialize(Base64.getDecoder().decode(transactionContext)));
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
String transactionContext = request.getHeader(TransactionContextConstants.TRANSACTION_CONTEXT);
if (StringUtils.isNotEmpty(transactionContext)) {
TransactionContextHolder.clear();
}
}
}
注意事项