1.传输上下文
在两个进程传输的过程中,例如A进程向B进程传输数据,一般都需要传一些固定字段信息,这些信息一般是与业务无关,像调用链追踪,api网关等都需要传输此上下文信息。我们现在有两个应用,应用A是订单系统,应用B是用户中台系统,而且我们是toB的业务,用户是属于某个企业的,该企业的唯一标识为corpId,每个应用对应一个唯一的应用id,还有多个应用的调用链追踪需要传输traceId等,所以A调用B必须传输此几个字段,以下介绍dubbo和feign传输上下文的方法。
2.dubbo
Dubbo(读音[ˈdʌbəʊ])是阿里巴巴公司开源的一个高性能优秀的服务框架使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现,具体想研究dubbo可以参考dubbo文档,本文只介绍dubbo传输上下文的方法:
#####DubboConsumer:
@Activate(group = Constants.CONSUMER)
public class DubboConsumerContextFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
Map<String, String> attachments = new HashMap<>();
attachments.put(xxx, xxx);
attachments.put(xxx, xxx);
//设置需要的内容
RpcContext.getContext().setAttachments(attachments);
return invoker.invoke(invocation);
}
}
#####DubboProvider:
@Activate(group = Constants.PROVIDER)
public class DubboProviderContextFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
logger.info("DbProviderContextFilter attachments={}", RpcContext.getContext().getAttachments());
String datasource = RpcContext.getContext().getAttachment(DbContextHolder.DATASOURCE_KEY);
String schema = RpcContext.getContext().getAttachment(DbContextHolder.SCHEMA_KEY);
if (StringUtils.isNotEmpty(datasource)) {
DbContextHolder.setDatasource(datasource);
}
if (StringUtils.isNotEmpty(schema)) {
DbContextHolder.setSchema(schema);
}
return invoker.invoke(invocation);
}
}
3.feign
@Component
public class FeignContextConfig implements RequestInterceptor {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private AppConfig appConfig;
@Override
public void apply(RequestTemplate requestTemplate) {
String corpId;
String userId = null;
AuthUser authUser = LoginContextHelper.getLoginUser();
if (authUser == null) {
corpId = MDC.get(SalaryConstants.CORP_ID);
} else {
corpId = authUser.getCorpId();
userId = authUser.getUserId();
}
String traceId = MDC.get(SalaryConstants.TRACE_ID);
requestTemplate.header("corpId", corpId);
requestTemplate.header("userId", encode(userId));
requestTemplate.header("appName", EnvironmentHelper.getApp());
requestTemplate.header("traceId", traceId);
requestTemplate.header("suiteId", appConfig.getSuiteId());
requestTemplate.header("appId", appConfig.getAppId());
}
/**
* userId存在中文,中文放在请求头中会出现乱码,需要编码
* @param userId
* @return
*/
private String encode(String userId) {
if (StringUtils.isEmpty(userId)) {
return userId;
}
try {
String encode = URLEncoder.encode(userId, "UTF-8");
return encode;
} catch (UnsupportedEncodingException e) {
logger.error("FeignContextConfig encode error, userId:{}", userId, e);
return userId;
}
}
注:采用http协议传输上下文信息,会将上下文字段设置到header,但是头信息中不能含有中文,所以需要进行编码后传输,然后在接受端解码。
网友评论