接上文“Feign封裝請求基本原理(啟動和注入)”,本文看一個Feign請求的過程。
一、遠程方法對應的MethodHandler創建
在注入Feign代理對象的bean時,會給@FeignClient注解接口下所有符合條件的方法生成對應的MethodHandler,該操作是在ReflectiveFeign#newInstance()方法中。
MethodHandler是遠程方法請求的實際處理器,這里是MethodHandler的實現類SynchronousMethodHandler的對象。
ReflectiveFeign#newInstance()方法
// ReflectiveFeign#newInstance(Target<T> target)
public <T> T newInstance(Target<T> target) {
// 該方法會生成遠程方法對應的MethodHandler
// ParseHandlersByName#apply(Target target)
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
// 省略了其他代碼
}
進入ReflectiveFeign$ParseHandlersByName#apply(Target target)方法
// ReflectiveFeign$ParseHandlersByName#apply(Target target)
// 本例中的target是 HardCodedTarget(type=FeignTest1Service, name=test1, url=http://hq.sinajs.cn)
public Map<String, MethodHandler> apply(Target target) {
// contract是SpringMvcContract對象,SpringMvcContract繼承Contract$BaseContract類
// 解析出每個方法對應的MethodMetadata
List<MethodMetadata> metadata = contract.parseAndValidateMetadata(target.type());
Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
for (MethodMetadata md : metadata) {
// 實現了RequestTemplate$Factory接口,有一個create()用於創建請求模板RequestTemplate實例
BuildTemplateByResolvingArgs buildTemplate;
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate =
new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
} else if (md.bodyIndex() != null) {
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
} else {
buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder, target);
}
if (md.isIgnored()) {
result.put(md.configKey(), args -> {
throw new IllegalStateException(md.configKey() + " is not a method handled by feign");
});
} else {
// factory.create()創建SynchronousMethodHandler實例
result.put(md.configKey(),
factory.create(target, md, buildTemplate, options, decoder, errorDecoder));
}
}
return result;
}
關於請求路徑、參數和頭信息的初始化處理多是在SpringMvcContract類中。
看解析接口方法MethodMetadata,進入SpringMvcContract#parseAndValidateMetadata(Class<?> targetType),即Contract$BaseContract#parseAndValidateMetadata(Class<?> targetType)
// Contract$BaseContract#parseAndValidateMetadata(Class<?> targetType)
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
// 不支持泛型 會拋異常
checkState(targetType.getTypeParameters().length == 0, "Parameterized types unsupported: %s",
targetType.getSimpleName());
// 實現的接口不能超過1個 會拋異常
checkState(targetType.getInterfaces().length <= 1, "Only single inheritance supported: %s",
targetType.getSimpleName());
// 實現了一個接口,那被實現接口不能再實現的接口 會拋異常
if (targetType.getInterfaces().length == 1) {
checkState(targetType.getInterfaces()[0].getInterfaces().length == 0,
"Only single-level inheritance supported: %s",
targetType.getSimpleName());
}
Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
// 遍歷所有public方法
for (Method method : targetType.getMethods()) {
// 合法的Feign方法不能是Object定義、靜態方法和接口默認方法
if (method.getDeclaringClass() == Object.class ||
(method.getModifiers() & Modifier.STATIC) != 0 ||
Util.isDefault(method)) {
continue;
}
// 解析出方法對應的 MethodMetadata。如解析請求path、produces、consumes和headers等,包括對類和方法上的注解
MethodMetadata metadata = parseAndValidateMetadata(targetType, method);
// 不支持重載方法 會拋異常
checkState(!result.containsKey(metadata.configKey()), "Overrides unsupported: %s",
metadata.configKey());
result.put(metadata.configKey(), metadata);
}
return new ArrayList<>(result.values());
}
二、遠程方法的調用
1. 發起請求

2. 代理對象調用處理方法
Map<Method, MethodHandler> dispatch該對象緩存了遠程方法請求的實際的處理邏輯,通過Method對象定位。
FeignInvocationHandler#invoke(Object proxy, Method method, Object[] args)

equals()、hashCode()和toString()方法不會被處理。
dispatch.get(method).invoke(args),也就是進入SynchronousMethodHandler#invoke(Object[] argv)

BuildTemplateByResolvingArgs#create(Object[] argv)

SynchronousMethodHandler#targetRequest(RequestTemplate template),攔截器執行

SynchronousMethodHandler#executeAndDecode(RequestTemplate template, Options options),發起請求和返回處理

3. 執行結果
