dubbo
的attachments
机制用于在业务请求之外传递附加信息,在很多场景下都有应用。本文尝试从源码角度解析rest
协议下,attachments
如何传递。
dubbo的attachments机制简介
dubbo
中有attachments
机制,在传递业务参数之外还可以传递附加信息,可以理解为像http
一样,在报文传送主要信息外,还有报文头
可传递附加信息。
dubbo
中attachments
示例为,在consumer
端放入:
RpcContext.getContext().setAttachment("test-attachment-key", "some-msg");
在provider
端取出:
Map 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 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 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
。