Feign是一种声明式、模板化的HTTP客户端。feign中文意思是模仿、假装的,顾名思义,它其实内部封装了http客户端,使得我们调用http请求时就像调用接口那么简单。来看一个简单的feign例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
   | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  import feign.Feign; import feign.Param; import feign.RequestLine; import feign.gson.GsonDecoder; import feign.gson.GsonEncoder;
  import java.io.Serializable; import java.util.List;
  public class FeignDemo {
      public static final String API_URL = "https://api.github.com";
           public static class Contributor implements Serializable {         public final String login;         public final int id;         public final String url;
          public Contributor(String login, int contributions, String url) {             this.login = login;             this.id = contributions;             this.url = url;         }
      }
      public interface GitHub {         @RequestLine("GET /repos/{owner}/{repo}/contributors")         List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repository);
      }
 
      public static void main(String[] args) {
          GitHub gitHub = Feign.builder()                 .encoder(new GsonEncoder())                 .decoder(new GsonDecoder())                 .target(GitHub.class, "https://api.github.com");
                            List<Contributor> contributors = gitHub.contributors("OpenFeign", "feign");         for (Contributor contributor : contributors) {             System.out.println("login name=" + contributor.login + ", id = " + contributor.id + ", page url = " + contributor.url);         }     } }
 
  | 
 
 以下是大神画的openfeign的原理图,openfeign核心也是feign,接下来我们根据这张图去看看源码如何实现的。本文源码基于feign 11.2解析。

1. 创建接口的代理类
  图中的@FeignClient是openfeign中的注解,后面会讲到。根据上面那个例子,从Feign.Builder()入手分析。Feign.Builder中定义了feign的一些属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
   |  private final List<RequestInterceptor> requestInterceptors =         new ArrayList<RequestInterceptor>();
  private Logger.Level logLevel = Logger.Level.NONE;
  private Contract contract = new Contract.Default();
  private Client client = new Client.Default(null, null);
  private Retryer retryer = new Retryer.Default();
  private Logger logger = new NoOpLogger();
  private Encoder encoder = new Encoder.Default();
  private Decoder decoder = new Decoder.Default();
  private QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder();
  private ErrorDecoder errorDecoder = new ErrorDecoder.Default();
  private Options options = new Options();
  private InvocationHandlerFactory invocationHandlerFactory =     new InvocationHandlerFactory.Default(); private boolean decode404; private boolean closeAfterDecode = true; private ExceptionPropagationPolicy propagationPolicy = NONE; private boolean forceDecoding = false; private List<Capability> capabilities = new ArrayList<>();
 
  | 
 
 接下来分析.target(GitHub.class, "https://api.github.com");target方法。我们可以看到,在target中,build()为feign的相关属性设置了默认值,newInstance最终掉到了feign.ReflectiveFeign#newInstance方法。该方法创建了目标方法的代理类,并为代理类绑定了调用方法MethodHandler。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
   |  public <T> T target(Target<T> target) {   return build().newInstance(target); }
 
  public Feign build() {      InvocationHandlerFactory invocationHandlerFactory =       Capability.enrich(this.invocationHandlerFactory, capabilities);   QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
    SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =       new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,           logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);      ParseHandlersByName handlersByName =       new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,           errorDecoder, synchronousMethodHandlerFactory);        return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder); }
 
    public <T> T newInstance(Target<T> target) {   	     Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);     Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();     List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>(); 	 	     for (Method method : target.type().getMethods()) {       if (method.getDeclaringClass() == Object.class) {         continue;       } else if (Util.isDefault(method)) {         DefaultMethodHandler handler = new DefaultMethodHandler(method);         defaultMethodHandlers.add(handler);         methodToHandler.put(method, handler);       } else {         methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));       }     }     InvocationHandler handler = factory.create(target, methodToHandler);          T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),         new Class<?>[] {target.type()}, handler);
      for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {       defaultMethodHandler.bindTo(proxy);     }          return proxy;   }
 
  | 
 
2. 依据Contract,解析底层MethodHandler
 Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);用来解析底层的MethodHandler,我们来看看apply方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
   | 
  public Map<String, MethodHandler> apply(Target target) {
    List<MethodMetadata> metadata = contract.parseAndValidateMetadata(target.type());   Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();         for (MethodMetadata md : metadata) {     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 {       result.put(md.configKey(),           factory.create(target, md, buildTemplate, options, decoder, errorDecoder));     }   }   return result; } }
 
  | 
 
2.1 解析注解
 主要对目标接口的注解、方法注解、参数注解进行解析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
   | 
  public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {         checkState(targetType.getTypeParameters().length == 0, "Parameterized types unsupported: %s",       targetType.getSimpleName());      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());   }   final Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();      for (final Method method : targetType.getMethods()) {     if (method.getDeclaringClass() == Object.class ||         (method.getModifiers() & Modifier.STATIC) != 0 ||         Util.isDefault(method)) {       continue;     }          final 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()); }
 
 
 
  protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {      final MethodMetadata data = new MethodMetadata();   data.targetType(targetType);   data.method(method);   data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));      data.configKey(Feign.configKey(targetType, method));
  	   if (targetType.getInterfaces().length == 1) {     processAnnotationOnClass(data, targetType.getInterfaces()[0]);   }   processAnnotationOnClass(data, targetType);
  	   for (final Annotation methodAnnotation : method.getAnnotations()) {     processAnnotationOnMethod(data, methodAnnotation, method);   }      if (data.isIgnored()) {     return data;   }            checkState(data.template().method() != null,       "Method %s not annotated with HTTP method type (ex. GET, POST)%s",       data.configKey(), data.warnings());      final Class<?>[] parameterTypes = method.getParameterTypes();   final Type[] genericParameterTypes = method.getGenericParameterTypes();
  	   final Annotation[][] parameterAnnotations = method.getParameterAnnotations();   final int count = parameterAnnotations.length;      for (int i = 0; i < count; i++) {     boolean isHttpAnnotation = false;     if (parameterAnnotations[i] != null) {            isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);     }
      if (isHttpAnnotation) {       data.ignoreParamater(i);     } 	     if (parameterTypes[i] == URI.class) {       data.urlIndex(i);     } else if (!isHttpAnnotation && parameterTypes[i] != Request.Options.class) {       if (data.isAlreadyProcessed(i)) {         checkState(data.formParams().isEmpty() || data.bodyIndex() == null,             "Body parameters cannot be used with form parameters.%s", data.warnings());       } else {         checkState(data.formParams().isEmpty(),             "Body parameters cannot be used with form parameters.%s", data.warnings());         checkState(data.bodyIndex() == null,             "Method has too many Body parameters: %s%s", method, data.warnings());         data.bodyIndex(i);         data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i]));       }     }   } 	   if (data.headerMapIndex() != null) {     checkMapString("HeaderMap", parameterTypes[data.headerMapIndex()],         genericParameterTypes[data.headerMapIndex()]);   } 	   if (data.queryMapIndex() != null) {     if (Map.class.isAssignableFrom(parameterTypes[data.queryMapIndex()])) {       checkMapKeys("QueryMap", genericParameterTypes[data.queryMapIndex()]);     }   }
    return data; }
 
  | 
 
 接下来看看,feign是如何对类注解、方法注解和参数注解进行解析的。从以上源码我们可以看到,在feign.DeclarativeContract类中的processAnnotationOnClass、processAnnotationOnMethod、processAnnotationsOnParameter三个方法中对以上三类注解进行了解析。这三个方法大同小异,都是获取定义好的注解解析器,然后调用process方法进行实际解析。
1 2 3 4 5 6 7 8 9
   | 
  List<GuardedAnnotationProcessor> processors = methodAnnotationProcessors.stream()     .filter(processor -> processor.test(annotation))     .collect(Collectors.toList());
  if (!processors.isEmpty()) {   processors.forEach(processor -> processor.process(annotation, data)); }
 
  | 
 
 源码我们可以看到方法解析器存储在methodAnnotationProcessorsmap中,那么它是什么时候被放进去的呢?这里往前看,在创建feign实例的时候会执行private Contract contract = new Contract.Default();,在Contract.Default()的构造方法中,把那三种注解解析器注册进了Contract的对应map中。
1 2 3 4 5 6 7
   |  public abstract class DeclarativeContract extends BaseContract {   private final List<GuardedAnnotationProcessor> classAnnotationProcessors = new ArrayList<>();   private final List<GuardedAnnotationProcessor> methodAnnotationProcessors = new ArrayList<>();   private final Map<Class<Annotation>, DeclarativeContract.ParameterAnnotationProcessor<Annotation>> parameterAnnotationProcessors =       new HashMap<>(); }
 
  | 
 
 Contract.Default继承自DeclarativeContract,从构造方法中可以看到,它的注册方式都是形如super.registerXXXAnnotation(AnnotationClass.class, param -> {})的方式,其中匿名函数param -> {}就是具体解析逻辑。我们跟踪super.registerClassAnnotation方法最终会看到register方法,方法注解和参数注解类似
1 2 3 4 5 6
   | protected <E extends Annotation> void registerClassAnnotation(Predicate<E> predicate,                                                                 DeclarativeContract.AnnotationProcessor<E> processor) {               this.classAnnotationProcessors.add(new GuardedAnnotationProcessor(predicate, processor));   }
 
  | 
 
 接下来我们看看具体的注解解析逻辑,代码位于feign.Contract.Default#Default{}中
            - 注册 类注解处理器到classAnnotationProcessors中
 
           
1 2 3 4 5 6 7 8 9 10 11 12
   |  super.registerClassAnnotation(Headers.class, (header, data) -> {      final String[] headersOnType = header.value();   checkState(headersOnType.length > 0, "Headers annotation was empty on type %s.",       data.configKey());      final Map<String, Collection<String>> headers = toMap(headersOnType);   headers.putAll(data.template().headers());   data.template().headers(null);    data.template().headers(headers); });
 
  | 
 
 总结:把@Header中数组取出,转成map赋值给requestTemplate
            - 注册 方法注解处理器到methodAnnotationProcessors中
 
           
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
   |  super.registerMethodAnnotation(RequestLine.class, (ann, data) -> {   final String requestLine = ann.value();   checkState(emptyToNull(requestLine) != null,       "RequestLine annotation was empty on method %s.", data.configKey());        final Matcher requestLineMatcher = REQUEST_LINE_PATTERN.matcher(requestLine);   if (!requestLineMatcher.find()) {     throw new IllegalStateException(String.format(         "RequestLine annotation didn't start with an HTTP verb on method %s",         data.configKey()));   } else {          data.template().method(HttpMethod.valueOf(requestLineMatcher.group(1)));     data.template().uri(requestLineMatcher.group(2));   }   data.template().decodeSlash(ann.decodeSlash());   data.template()       .collectionFormat(ann.collectionFormat()); });
 
 
  super.registerMethodAnnotation(Body.class, (ann, data) -> {   final String body = ann.value();   checkState(emptyToNull(body) != null, "Body annotation was empty on method %s.",       data.configKey());      if (body.indexOf('{') == -1) {     data.template().body(body);   } else {     data.template().bodyTemplate(body);   } });
 
 
  super.registerMethodAnnotation(Headers.class, (header, data) -> {   final String[] headersOnMethod = header.value();   checkState(headersOnMethod.length > 0, "Headers annotation was empty on method %s.",       data.configKey());      data.template().headers(toMap(headersOnMethod)); });
 
  | 
 
 总结:
- @RequestLine:解析值,并将method和uri赋值给请求(requestTemplate)
 
- @Body:设置请求体的值和编码
 
- @Headers:设置请求的header
            - 注册 参数注解处理器到parameterAnnotationProcessors中
 
           
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
   |  super.registerParameterAnnotation(Param.class, (paramAnnotation, data, paramIndex) -> {   final String annotationName = paramAnnotation.value();   final Parameter parameter = data.method().getParameters()[paramIndex];   final String name;   if (emptyToNull(annotationName) == null && parameter.isNamePresent()) {     name = parameter.getName();   } else {     name = annotationName;   }   checkState(emptyToNull(name) != null, "Param annotation was empty on param %s.",       paramIndex);   nameParam(data, name, paramIndex);   final Class<? extends Param.Expander> expander = paramAnnotation.expander();   if (expander != Param.ToStringExpander.class) {     data.indexToExpanderClass().put(paramIndex, expander);   }      if (!data.template().hasRequestVariable(name)) {     data.formParams().add(name);   } });
 
 
  super.registerParameterAnnotation(QueryMap.class, (queryMap, data, paramIndex) -> {   checkState(data.queryMapIndex() == null,       "QueryMap annotation was present on multiple parameters.");      data.queryMapIndex(paramIndex);   data.queryMapEncoded(queryMap.encoded()); });
 
 
  super.registerParameterAnnotation(HeaderMap.class, (queryMap, data, paramIndex) -> {   checkState(data.headerMapIndex() == null,       "HeaderMap annotation was present on multiple parameters.");      data.headerMapIndex(paramIndex); });
 
  | 
 
总结:不总结了,类似method,都是给request设置响应属性值。 
 从源码我们可以看到默认的请求协议包含的6种注解,分别是@Header、@RequestLine、@Body、@Headers、@Param、@QueryMap、@HeaderMap,他们对应着三类解析器。实际工作中,我们也可以定义自己的Contract协议,只需要实现Contract接口即可,比如openfeign就是使用这种方式,集成了spring mvc的相关注解进去。
2.2 为代理类设置MethodHandler
 这个很简单,主要是通过工厂创建MethodHandler。factory.create(target, md, buildTemplate, options, decoder, errorDecoder));,这里的factory是new Feign.Build的时候创建的,它是一个同步方法处理工厂SynchronousMethodHandler。接下来我们看看它的create代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
   |     public MethodHandler create(Target<?> target,                                 MethodMetadata md,                                 RequestTemplate.Factory buildTemplateFromArgs,                                 Options options,                                 Decoder decoder,                                 ErrorDecoder errorDecoder) { 			       return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger,           logLevel, md, buildTemplateFromArgs, options, decoder,           errorDecoder, decode404, closeAfterDecode, propagationPolicy, forceDecoding);     }     
 
  final class SynchronousMethodHandler implements MethodHandler {   private final MethodMetadata metadata;   private final Target<?> target;   private final Client client;   private final Retryer retryer;   private final List<RequestInterceptor> requestInterceptors;   private final Logger logger;   private final Logger.Level logLevel;   private final RequestTemplate.Factory buildTemplateFromArgs;   private final Options options;   private final ExceptionPropagationPolicy propagationPolicy;
       private final Decoder decoder;   private final AsyncResponseHandler asyncResponseHandler;
 
  | 
 
 SynchronousMethodHandler继承自MethodHandler,因此方法的调用是在这个类的invoke中进行的。里面包含了图中request构造、编码、请求拦截、response解码等都在里面。
3. 方法的调用和返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   | @Override public Object invoke(Object[] argv) throws Throwable {      RequestTemplate template = buildTemplateFromArgs.create(argv);      Options options = findOptions(argv);      Retryer retryer = this.retryer.clone();   while (true) {     try {              return executeAndDecode(template, options);     } catch (RetryableException e) {       try {                  retryer.continueOrPropagate(e);       } catch (RetryableException th) {         Throwable cause = th.getCause();         if (propagationPolicy == UNWRAP && cause != null) {           throw cause;         } else {           throw th;         }       }       if (logLevel != Logger.Level.NONE) {       	         logger.logRetry(metadata.configKey(), logLevel);       }       continue;     }   } }
 
  | 
 
3.1 构造request请求
 buildTemplateFromArgs.create(argv);这一句构造request请求,前面分析元数据中也有requestTemplate,它只是临时的,,通过它构造真正的请求。argv是调用方法时传入的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
   | @Override public RequestTemplate create(Object[] argv) { 	 	   RequestTemplate mutable = RequestTemplate.from(metadata.template());      mutable.feignTarget(target);   if (metadata.urlIndex() != null) {     int urlIndex = metadata.urlIndex();     checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex);     mutable.target(String.valueOf(argv[urlIndex]));   }         Map<String, Object> varBuilder = new LinkedHashMap<String, Object>();   for (Entry<Integer, Collection<String>> entry : metadata.indexToName().entrySet()) {     int i = entry.getKey();     Object value = argv[entry.getKey()];     if (value != null) {        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) {               Object value = argv[metadata.queryMapIndex()];     Map<String, Object> queryMap = toQueryMap(value);     template = addQueryMapQueryParameters(queryMap, template);   }      if (metadata.headerMapIndex() != null) {     template =         addHeaderMapHeaders((Map<String, Object>) argv[metadata.headerMapIndex()], template);   } 	   return template; }
 
  | 
 
3.2 发起请求并解析响应
 设置参数和获取重试器都很简单,分析省略。直接看executeAndDecode方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
   | Object executeAndDecode(RequestTemplate template, Options options) throws Throwable { 	 	   Request request = targetRequest(template);
    if (logLevel != Logger.Level.NONE) {     logger.logRequest(metadata.configKey(), logLevel, request);   }
    Response response;   long start = System.nanoTime();   try {   	   	   	
 
 
 
 
 
      response = client.execute(request, options);          response = response.toBuilder()         .request(request)         .requestTemplate(template)         .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);
 
    if (decoder != null)     return decoder.decode(response, metadata.returnType());
 
    CompletableFuture<Object> resultFuture = new CompletableFuture<>();   asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,       metadata.returnType(),       elapsedTime);
    try {     if (!resultFuture.isDone())       throw new IllegalStateException("Response handling not done");
      return resultFuture.join();   } catch (CompletionException e) {     Throwable cause = e.getCause();     if (cause != null)       throw cause;     throw e;   } }
 
  | 
 
 我们来看第五步,解析response并解码源码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
   | void handleResponse(CompletableFuture<Object> resultFuture,                   String configKey,                   Response response,                   Type returnType,                   long elapsedTime) {
  boolean shouldClose = true;
  try {   if (logLevel != Level.NONE) {     response = logger.logAndRebufferResponse(configKey, logLevel, response,         elapsedTime);   }      if (Response.class == returnType) {   	     if (response.body() == null) {       resultFuture.complete(response);     } else if (response.body().length() == null         || response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {       shouldClose = false;       resultFuture.complete(response);     } else {              final byte[] bodyData = Util.toByteArray(response.body().asInputStream());       resultFuture.complete(response.toBuilder().body(bodyData).build());     }        } else if (response.status() >= 200 && response.status() < 300) {     if (isVoidType(returnType)) {       resultFuture.complete(null);     } else {          
 
 
 
 
        final Object result = decode(response, returnType);       shouldClose = closeAfterDecode;              resultFuture.complete(result);     }        } else if (decode404 && response.status() == 404 && !isVoidType(returnType)) {     final Object result = decode(response, returnType);     shouldClose = closeAfterDecode;     resultFuture.complete(result);   } else {          resultFuture.completeExceptionally(errorDecoder.decode(configKey, response));   } } catch (final IOException e) {   if (logLevel != Level.NONE) {     logger.logIOException(configKey, logLevel, e, elapsedTime);   }   resultFuture.completeExceptionally(errorReading(response.request(), response, e)); } catch (final Exception e) {   resultFuture.completeExceptionally(e); } finally {   if (shouldClose) {     ensureClosed(response.body());   } }
  }
 
  | 
 
  以上就是feign的工作原理了,基本上和流程图一致,图中没涉及到的@EnableClient和最后的负载均衡,后面解析openfeign原理会讲到。画个图总结下:
