本文接上一篇静态主线,来继续看feign是如何进行网络调用的。
上文说到将所有的方法与模板都绑定到feign.ReflectiveFeign.FeignInvocationHandler
代理类上了。这篇就从这块说起:
从feign.ReflectiveFeign.FeignInvocationHandler#invoke
调用,代码如下:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//对Object的方法进行处理,已省略
//dispatch就是Map<Method, MethodHandler>类型,会根据方法交给对应的MethodHandler
return dispatch.get(method).invoke(args);
}
下一步跳转到feign.SynchronousMethodHandler#invoke
中:
@Override
public Object invoke(Object[] argv) throws Throwable {
//构建RequestTemplate,buildTemplateFromArgs为RequestTemplate.Factory的实例
RequestTemplate template = buildTemplateFromArgs.create(argv);
//重试机制
Retryer retryer = this.retryer.clone();
while (true) {
try {
return executeAndDecode(template);
} catch (RetryableException e) {
retryer.continueOrPropagate(e);
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
@Override
public RequestTemplate create(Object[] argv) {
RequestTemplate mutable = new RequestTemplate(metadata.template());
if (metadata.urlIndex() != null) {
int urlIndex = metadata.urlIndex();
checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex);
mutable.insert(0, String.valueOf(argv[urlIndex]));
}
Map<String, Object> varBuilder = new LinkedHashMap<String, Object>();
//填充参数到变量map中
for (Entry<Integer, Collection<String>> entry : metadata.indexToName().entrySet()) {
int i = entry.getKey();
Object value = argv[entry.getKey()];
if (value != null) { // Null values are skipped.
if (indexToExpander.containsKey(i)) {
//转换参数中的值为需要的类型
value = expandElements(indexToExpander.get(i), value);
}
for (String name : entry.getValue()) {
varBuilder.put(name, value);
}
}
}
//解析模板路径
RequestTemplate template = resolve(argv, mutable, varBuilder);
if (metadata.queryMapIndex() != null) {
// add query map parameters after initial resolve so that they take
// precedence over any predefined values
template = addQueryMapQueryParameters((Map<String, Object>) argv[metadata.queryMapIndex()], template);
}
if (metadata.headerMapIndex() != null) {
template = addHeaderMapHeaders((Map<String, Object>) argv[metadata.headerMapIndex()], template);
}
return template;
}
RequestTemplate resolve(Map<String, ?> unencoded, Map<String, Boolean> alreadyEncoded) {
//替换query中的参数,即?后面拼接的参数
replaceQueryValues(unencoded, alreadyEncoded);
Map<String, String> encoded = new LinkedHashMap<String, String>();
//参数编码
for (Entry<String, ?> entry : unencoded.entrySet()) {
final String key = entry.getKey();
final Object objectValue = entry.getValue();
String encodedValue = encodeValueIfNotEncoded(key, objectValue, alreadyEncoded);
encoded.put(key, encodedValue);
}
//此处挨个字符查找{,拼接值,忽略和}的中间部分,拼接}后面部分
String resolvedUrl = expand(url.toString(), encoded).replace("+", "%20");
if (decodeSlash) {
resolvedUrl = resolvedUrl.replace("%2F", "/");
}
url = new StringBuilder(resolvedUrl);
Map<String, Collection<String>> resolvedHeaders = new LinkedHashMap<String, Collection<String>>();
//处理head部分
for (String field : headers.keySet()) {
Collection<String> resolvedValues = new ArrayList<String>();
for (String value : valuesOrEmpty(headers, field)) {
String resolved = expand(value, unencoded);
resolvedValues.add(resolved);
}
resolvedHeaders.put(field, resolvedValues);
}
headers.clear();
headers.putAll(resolvedHeaders);
if (bodyTemplate != null) {
body(urlDecode(expand(bodyTemplate, encoded)));
}
return this;
}
执行请求,并对响应进行解码的过程,代码feign.SynchronousMethodHandler#executeAndDecode
如下:
Object executeAndDecode(RequestTemplate template) throws Throwable {
//拼接完整的request请求
Request request = targetRequest(template);
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
Response response;
long start = System.nanoTime();
try {
//由LoadBalancerFeignClient发送请求,默认是连接1000毫秒,读超时30000毫秒。
response = client.execute(request, options);
// ensure the request is set. TODO: remove in Feign 10
response.toBuilder().request(request).build();
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
throw errorExecuting(request, e);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
//设置关闭流标志
boolean shouldClose = true;
try {
if (logLevel != Logger.Level.NONE) {
response =
logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);
// ensure the request is set. TODO: remove in Feign 10
response.toBuilder().request(request).build();
}
//对响应解码,已省略
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
}
throw errorReading(request, response, e);
} finally {
//关闭响应流
if (shouldClose) {
ensureClosed(response.body());
}
}
}
获取feign配置并发送请求,下面是org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient#execute
代码:
@Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
URI asUri = URI.create(request.url());
String clientName = asUri.getHost();
URI uriWithoutHost = cleanUrl(request.url(), clientName);
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
this.delegate, request, uriWithoutHost);
IClientConfig requestConfig = getClientConfig(options, clientName);
return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
requestConfig).toResponse();
}
catch (ClientException e) {
IOException io = findIOException(e);
if (io != null) {
throw io;
}
throw new RuntimeException(e);
}
}
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);
try {
return command.submit(
new ServerOperation<T>() {
@Override
public Observable<T> call(Server server) {
//构建HTTP的url,并在最后用HTTPConnection完成请求
URI finalUri = reconstructURIWithServer(server, request.getUri());
S requestForServer = (S) request.replaceUri(finalUri);
try {
return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
}
catch (Exception e) {
return Observable.error(e);
}
}
})
.toBlocking()
.single();
} catch (Exception e) {
Throwable t = e.getCause();
if (t instanceof ClientException) {
throw (ClientException) t;
} else {
throw new ClientException(e);
}
}
}