- 从
ReflectiveFeign
中看到实现将接口方法解析成Rest
请求的核心逻辑在这行代码:
//核心逻辑入口,反射解析目标Class,得到MethodHandler集合
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
interface MethodHandler {
Object invoke(Object[] argv) throws Throwable;
}
- 只有一个
invoke
方法,和Proxy
的定义类似。
- 实现
Rest
请求的实现类为SynchronousMethodHandler
,实现方法为:
@Override
public Object invoke(Object[] argv) throws Throwable {
//根据输入参数组装成HTTP请求模版
RequestTemplate template = buildTemplateFromArgs.create(argv);
Retryer retryer = this.retryer.clone(); //重试策略
while (true) {
try {
//执行HTTP请求并解析结果,返回
return executeAndDecode(template);
} catch (RetryableException e) {
retryer.continueOrPropagate(e); //重试策略
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
-
RequestTemplate
:封装REST
请求模版,包括HTTP
协议中请求需要的信息。
-
buildTemplateFromArgs.create(argv)
:输入参数有可能是HTTP
中的Path
,Parameter
,Header
,Body
等参数。每个参数按顺序,代表的意义是在API
接口定义时,由形参上的标签(Annotation
)决定的。
-
executeAndDecode(template)
:执行并解析HTTP
结果,这个类的核心逻辑:
Object executeAndDecode(RequestTemplate template) throws Throwable {
//生成请求实例
Request request = targetRequest(template);
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
Response response;
long start = System.nanoTime();
try {
//发起REST请求,得到响应
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();
}
if (Response.class == metadata.returnType()) {
if (response.body() == null) {
return response;
}
if (response.body().length() == null ||
response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
shouldClose = false;
return response;
}
// Ensure the response body is disconnected
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
return response.toBuilder().body(bodyData).build();
}
//请求成功的响应处理
if (response.status() >= 200 && response.status() < 300) {
if (void.class == metadata.returnType()) {
return null;
} else {
//解析成需要的对象返回
return decode(response);
}
}
//404的响应单独处理
else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
return decode(response);
} else {
//错误响应时,转换为指定的异常对象
throw errorDecoder.decode(metadata.configKey(), response);
}
} 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());
}
}
}
-
Request
和Response
:Feign
对REST
请求响应的封装。
-
client.execute(request, options)
:HTTP
请求实际发生的步骤,client
是HTTP
请求客户端的抽象,实际使用的HTTP
框架是由使用者定义,支持的包括有:Java
原生,OkHttp
, ApacheHttpClient
等。
-
return decode(response)
:成功的响应内容转换成API
定义的出参对象。
-
if (decode404 && response.status() == 404 && void.class != metadata.returnType())
:在REST
规范中,一般将找不到资源实现为返回404 NOT FOUND
错误。因此404
错误被认为是一种业务范畴里的正常响应,所以Feign
对404
错误做了单独处理。
网友评论