- 從
ReflectiveFeign
中看到實現(xiàn)將接口方法解析成Rest
請求的核心邏輯在這行代碼:
//核心邏輯入口紧阔,反射解析目標Class,得到MethodHandler集合
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
interface MethodHandler {
Object invoke(Object[] argv) throws Throwable;
}
- 只有一個
invoke
方法剃根,和Proxy
的定義類似。
- 實現(xiàn)
Rest
請求的實現(xiàn)類為SynchronousMethodHandler
狈醉,實現(xiàn)方法為:
@Override
public Object invoke(Object[] argv) throws Throwable {
//根據(jù)輸入?yún)?shù)組裝成HTTP請求模版
RequestTemplate template = buildTemplateFromArgs.create(argv);
Retryer retryer = this.retryer.clone(); //重試策略
while (true) {
try {
//執(zhí)行HTTP請求并解析結果,返回
return executeAndDecode(template);
} catch (RetryableException e) {
retryer.continueOrPropagate(e); //重試策略
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
-
RequestTemplate
:封裝REST
請求模版惠险,包括HTTP
協(xié)議中請求需要的信息。
-
buildTemplateFromArgs.create(argv)
:輸入?yún)?shù)有可能是HTTP
中的Path
班巩,Parameter
渣慕,Header
,Body
等參數(shù)逊桦。每個參數(shù)按順序,代表的意義是在API
接口定義時强经,由形參上的標簽(Annotation
)決定的睡陪。
-
executeAndDecode(template)
:執(zhí)行并解析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 {
//發(fā)起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
請求實際發(fā)生的步驟转砖,client
是HTTP
請求客戶端的抽象须鼎,實際使用的HTTP
框架是由使用者定義府蔗,支持的包括有:Java
原生晋控,OkHttp
, ApacheHttpClient
等姓赤。
-
return decode(response)
:成功的響應內(nèi)容轉換成API
定義的出參對象。
-
if (decode404 && response.status() == 404 && void.class != metadata.returnType())
:在REST
規(guī)范中不铆,一般將找不到資源實現(xiàn)為返回404 NOT FOUND
錯誤蝌焚。因此404
錯誤被認為是一種業(yè)務范疇里的正常響應誓斥,所以Feign
對404
錯誤做了單獨處理只洒。
最后編輯于 :
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者