dubbo的attachments机制用于在业务请求之外传递附加信息,在很多场景下都有应用。本文尝试从源码角度解析rest协议下,attachments如何传递。
dubbo的attachments机制简介
dubbo中有attachments机制,在传递业务参数之外还可以传递附加信息,可以理解为像http一样,在报文传送主要信息外,还有报文头可传递附加信息。
dubbo中attachments示例为,在consumer端放入:
RpcContext.getContext().setAttachment("test-attachment-key", "some-msg");
在provider端取出:
Map<String, String> attachments = RpcContext.getContext().getAttachments();
rest下如何传递
dubbo-protocol-rest可以让dubbo使用rest方式提供和使用服务,同样也支持attachments机制,键值对位于http报文头,日志形如:
DEBUG org.apache.http.headers - http-outgoing-0 >> GET /restService/sayHello?name=gxk HTTP/1.1
DEBUG org.apache.http.headers - http-outgoing-0 >> Accept: application/json;charset=UTF-8
DEBUG org.apache.http.headers - http-outgoing-0 >> Dubbo-Attachments: test-attachment-key=some-msg
DEBUG org.apache.http.headers - http-outgoing-0 >> Host: 124.126.21.38:8080
DEBUG org.apache.http.headers - http-outgoing-0 >> Connection: Keep-Alive
DEBUG org.apache.http.headers - http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.2 (Java/11.0.2)
DEBUG org.apache.http.headers - http-outgoing-0 >> Accept-Encoding: gzip,deflate
注意其中第3行即为使用http报文头方式传递attachments
Dubbo-Attachments: test-attachment-key=some-msg
具体到代码实现,见com.alibaba.dubbo.rpc.protocol.rest.RpcContextFilter,源码片段如下:
public class RpcContextFilter implements ContainerRequestFilter, ClientRequestFilter {
private static final String DUBBO_ATTACHMENT_HEADER = "Dubbo-Attachments";
// 略
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// 略
String headers = requestContext.getHeaderString(DUBBO_ATTACHMENT_HEADER);
if (headers != null) {
for (String header : headers.split(",")) {
int index = header.indexOf("=");
if (index > 0) {
String key = header.substring(0, index);
String value = header.substring(index + 1);
if (!StringUtils.isEmpty(key)) {
RpcContext.getContext().setAttachment(key.trim(), value.trim());
}
}
}
}
}
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
int size = 0;
for (Map.Entry<String, String> entry : RpcContext.getContext().getAttachments().entrySet()) {
// 略
String attachments = entry.getKey() + "=" + entry.getValue();
requestContext.getHeaders().add(DUBBO_ATTACHMENT_HEADER, attachments);
}
}
}
两个函数依次为作为服务端和客户端如何处理attachments,可见rest方式下,attachments主要和RpcContext打交道:
- 作为服务端,从
http报文头中取出Dubbo-Attachments的内容,将形如a=b,c=d的内容放入RpcContext - 作为客户端,从
RpcContext中取出所有键值对,放入http报文头的Dubbo-Attachments
另外,在com.alibaba.dubbo.rpc.filter.ContextFilter中,可见将Invocation中的attachments放入了RpcContext,代码片段如下:
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
Map<String, String> attachments = invocation.getAttachments();
// 略
// mreged from dubbox
// we may already added some attachments into RpcContext before this filter (e.g. in rest protocol)
if (attachments != null) {
if (RpcContext.getContext().getAttachments() != null) {
RpcContext.getContext().getAttachments().putAll(attachments);
} else {
RpcContext.getContext().setAttachments(attachments);
}
}
// 略
}
上述两个组件,RpcContextFilter作用于http请求,回调时机早于ContextFilter等dubbo的filter。