Spring OpenFeign源码分析(2) 接口代理执行流程

前文《OpenFeign源码01 接口扫描和创建代理》中分析了创建feign代理的流程,本文将从代理ReflectiveFeign.FeignInvocationHandler(实现了InvocationHandler接口)入手,分析feign client的执行流程:

  1. SynchronousMethodHandler类的invoke方法
  2. 执行拦截器的逻辑并获取feign Request
  3. LoadBalancer负载均衡逻辑
  4. 发送请求
  5. 响应解码

回顾创建Client代理

《OpenFeign源码01 接口扫描和创建代理》中已经分析过,Feign使用jdk proxy为Client创建代理对象:

// 使用InvocationHandlerFactory创建InvocationHandler
// 默认情况下使用的InvocationHandlerFactory.Default工厂
// 这个Default工厂创建的是ReflectiveFeign.FeignInvocationHandler对象
// 后续介绍hytrix和sentinel时,他们注入的InvocationHandlerFactory会不同
InvocationHandler handler = factory.create(target, methodToHandler);
// 使用jdk proxy创建代理
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
	new Class<?>[] {target.type()}, handler);

Feign中InvocationHandlerFactory用于创建InvocationHandler。

这个接口默认使用feign.InvocationHandlerFactory.Default实现类,另外在与Hytrix、Sentinel整合时,Hytrix、Sentinel会使用自己的逻辑覆盖默认实现。

本文还是分析Default这个类:

static final class Default implements InvocationHandlerFactory {

  @Override
  public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
    return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
  }
}

ReflectiveFeign.FeignInvocationHandler类实现了InvocationHandler接口,封装代理逻辑:

static class FeignInvocationHandler implements InvocationHandler {

  // HardCodedTarget对象,封装FeignClient类型、name、url等信息
  // apply方法可以对RequestTemplate做一些处理,然后获取到Request对象
  private final Target target;

  // 封装接口Method -> MethodHandler映射关系,用于分发请求
  private final Map<Method, MethodHandler> dispatch;

  FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
	this.target = checkNotNull(target, "target");
	this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 判断equals、hashCode、toString方法,则不使用dispatch分发

    // 查找MethodHandler并调用invoke分发处理请求
	return dispatch.get(method).invoke(args);
  }
}

dispatch封装接口Method -> MethodHandler映射关系,其中MethodHandler是SynchronousMethodHandler类型的对象。

SynchronousMethodHandler类

SynchronousMethodHandler类概述

实现了MethodHandler接口,这个接口有一个invoke方法,允许传入Object[]数组参数:

interface MethodHandler {

  Object invoke(Object[] argv) throws Throwable;
}

Object[] argv就是feign客户端接口传递的参数。

Object返回值就是服务端的响应内容。

SynchronousMethodHandler类封装了以下信息:

final class SynchronousMethodHandler implements MethodHandler {

  // 接口方法元数据信息
  private final MethodMetadata metadata;
  // Target用于获取url、name、type等信息,能够将RequestTemplate转为Request
  private final Target<?> target;
  // 处理HTTP请求
  private final Client client;
  // 重试配置
  private final Retryer retryer;
  // 拦截器
  private final List<RequestInterceptor> requestInterceptors;
  private final Logger logger;
  private final Logger.Level logLevel;
  // 使用接口方法入参创建RequestTemplate
  private final RequestTemplate.Factory buildTemplateFromArgs;
  private final Options options;
  private final ExceptionPropagationPolicy propagationPolicy;

  // 用于处理响应
  // only one of decoder and asyncResponseHandler will be non-null
  private final Decoder decoder;
  private final AsyncResponseHandler asyncResponseHandler;

  private SynchronousMethodHandler(Target<?> target, Client client, Retryer retryer,
      List<RequestInterceptor> requestInterceptors, Logger logger,
      Logger.Level logLevel, MethodMetadata metadata,
      RequestTemplate.Factory buildTemplateFromArgs, Options options,
      Decoder decoder, ErrorDecoder errorDecoder, boolean decode404,
      boolean closeAfterDecode, ExceptionPropagationPolicy propagationPolicy,
      boolean forceDecoding) {

    this.target = checkNotNull(target, "target");
    this.client = checkNotNull(client, "client for %s", target);
    this.retryer = checkNotNull(retryer, "retryer for %s", target);
    this.requestInterceptors =
        checkNotNull(requestInterceptors, "requestInterceptors for %s", target);
    this.logger = checkNotNull(logger, "logger for %s", target);
    this.logLevel = checkNotNull(logLevel, "logLevel for %s", target);
    this.metadata = checkNotNull(metadata, "metadata for %s", target);
    this.buildTemplateFromArgs = checkNotNull(buildTemplateFromArgs, "metadata for %s", target);
    this.options = checkNotNull(options, "options for %s", target);
    this.propagationPolicy = propagationPolicy;

    // 总是false
    if (forceDecoding) {
      // internal only: usual handling will be short-circuited, and all responses will be passed to
      // decoder directly!
      this.decoder = decoder;
      this.asyncResponseHandler = null;
    } else {
      this.decoder = null;
      this.asyncResponseHandler = new AsyncResponseHandler(logLevel, logger, decoder, errorDecoder,
          decode404, closeAfterDecode);
    }
  }
}

invoke方法

public Object invoke(Object[] argv) throws Throwable {
  // 使用argv构建RequestTemplate
  // 通过RequestTemplate的request()方法可以获取到请求对象
  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;
        }
      }
      continue;
    }
  }
}

// 我们重点分析这个方法
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
  // 1. 执行拦截器的逻辑并获取Request
  Request request = targetRequest(template);

  Response response;
  long start = System.nanoTime();
  try {
    // 2. 使用Client执行http请求,这里是LoadBalancerFeignClient对象
    response = client.execute(request, options);
    // ensure the request is set. TODO: remove in Feign 12
    // 高版本移除
    response = response.toBuilder()
        .request(request)
        .requestTemplate(template)
        .build();
  } catch (IOException e) {
    // 向上抛错执行重试逻辑
    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对象
  // 3. 解码响应
  asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
      metadata.returnType(),
      elapsedTime);

  try {
    if (!resultFuture.isDone())
      throw new IllegalStateException("Response handling not done");

    // join等待
    return resultFuture.join();
  } catch (CompletionException e) {
    Throwable cause = e.getCause();
    if (cause != null)
      throw cause;
    throw e;
  }
}

流程:

  1. 执行拦截器的逻辑并获取Request
  2. 使用Client执行http请求,这里是LoadBalancerFeignClient对象
  3. 响应解码

executeAndDecode流程分析

执行拦截器的逻辑并获取Request

// 1. 执行拦截器的逻辑并获取Request
Request request = targetRequest(template);

targetRequest方法:

Request targetRequest(RequestTemplate template) {
  // 可以使用拦截器添加header、打印日志等
  // 《Feign拦截器和解码器》
  // https://www.cnblogs.com/xugf/p/13458520.html
  for (RequestInterceptor interceptor : requestInterceptors) {
    interceptor.apply(template);
  }
  // HardCodedTarget的apply方法
  return target.apply(template);
}

使用Client执行http请求

流程概览

// 2. 使用Client执行http请求,这里是LoadBalancerFeignClient对象
response = client.execute(request, options);

这里的client是LoadBalancerFeignClient对象,以OkHttpClient为例:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnProperty("feign.okhttp.enabled")
@Import(OkHttpFeignConfiguration.class)
class OkHttpFeignLoadBalancedConfiguration {

	@Bean
	@ConditionalOnMissingBean(Client.class)
	public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
			SpringClientFactory clientFactory, okhttp3.OkHttpClient okHttpClient) {
		OkHttpClient delegate = new OkHttpClient(okHttpClient);
        // 这里装饰了一下
		return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
	}
}

execute方法:

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);
        // 1. 获取FeignLoadBalancer
        // 2. 查找可用服务节点、负载均衡、发送请求等
		return lbClient(clientName)
				.executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
	} catch (ClientException e) {
		IOException io = findIOException(e);
		if (io != null) {
			throw io;
		}
		throw new RuntimeException(e);
	}
}

获取FeignLoadBalancer

逻辑在CachingSpringLoadBalancerFactory中:

public FeignLoadBalancer create(String clientName) {
    // 使用clientName(即serviceId)在缓存里面查找
	FeignLoadBalancer client = this.cache.get(clientName);
	if (client != null) {
		return client;
	}
    // 从容器里面获取查找相关配置
	IClientConfig config = this.factory.getClientConfig(clientName);
    // 负载均衡器,他负责管理可用节点、负载均衡等
    // 默认使用的是ZoneAwareLoadBalancer类型,默认使用的IRule是ZoneAvoidanceRule类型
    // 在RibbonClientConfiguration中装配
	ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
	ServerIntrospector serverIntrospector = this.factory.getInstance(clientName,
			ServerIntrospector.class);
    // 创建FeignLoadBalancer
    // RetryableFeignLoadBalancer依赖spring-retry包,暂不分析
	client = this.loadBalancedRetryFactory != null
			? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
					this.loadBalancedRetryFactory)
			: new FeignLoadBalancer(lb, config, serverIntrospector);
    // 放入缓存
	this.cache.put(clientName, client);
	return client;
}

RibbonClientConfiguration配置类:

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@Import({ HttpClientConfiguration.class, OkHttpRibbonConfiguration.class,
		RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class })
public class RibbonClientConfiguration {

	/**
	 * Ribbon client default connect timeout.
	 */
	public static final int DEFAULT_CONNECT_TIMEOUT = 1000;

	/**
	 * Ribbon client default read timeout.
	 */
	public static final int DEFAULT_READ_TIMEOUT = 1000;

	/**
	 * Ribbon client default Gzip Payload flag.
	 */
	public static final boolean DEFAULT_GZIP_PAYLOAD = true;

	@RibbonClientName
	private String name = "client";

	@Autowired
	private PropertiesFactory propertiesFactory;

	@Bean
	@ConditionalOnMissingBean
	public IClientConfig ribbonClientConfig() {
		DefaultClientConfigImpl config = new DefaultClientConfigImpl();
		config.loadProperties(this.name);
		config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT);
		config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);
		config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD);
		return config;
	}

    /* IRule - 负载均衡策略 */
	@Bean
	@ConditionalOnMissingBean
	public IRule ribbonRule(IClientConfig config) {
		if (this.propertiesFactory.isSet(IRule.class, name)) {
			return this.propertiesFactory.get(IRule.class, config, name);
		}
		ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
		rule.initWithNiwsConfig(config);
		return rule;
	}

	@Bean
	@ConditionalOnMissingBean
	public IPing ribbonPing(IClientConfig config) {
		if (this.propertiesFactory.isSet(IPing.class, name)) {
			return this.propertiesFactory.get(IPing.class, config, name);
		}
		return new DummyPing();
	}

	@Bean
	@ConditionalOnMissingBean
	@SuppressWarnings("unchecked")
	public ServerList<Server> ribbonServerList(IClientConfig config) {
		if (this.propertiesFactory.isSet(ServerList.class, name)) {
			return this.propertiesFactory.get(ServerList.class, config, name);
		}
		ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();
		serverList.initWithNiwsConfig(config);
		return serverList;
	}

    /* 更新可用server */
	@Bean
	@ConditionalOnMissingBean
	public ServerListUpdater ribbonServerListUpdater(IClientConfig config) {
		return new PollingServerListUpdater(config);
	}

    /* ILoadBalancer */
	@Bean
	@ConditionalOnMissingBean
	public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
			ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
			IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
		if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
			return this.propertiesFactory.get(ILoadBalancer.class, config, name);
		}
		return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
				serverListFilter, serverListUpdater);
	}

	@Bean
	@ConditionalOnMissingBean
	@SuppressWarnings("unchecked")
	public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
		if (this.propertiesFactory.isSet(ServerListFilter.class, name)) {
			return this.propertiesFactory.get(ServerListFilter.class, config, name);
		}
		ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
		filter.initWithNiwsConfig(config);
		return filter;
	}

    /* RibbonLoadBalancerContext */
	@Bean
	@ConditionalOnMissingBean
	public RibbonLoadBalancerContext ribbonLoadBalancerContext(ILoadBalancer loadBalancer,
			IClientConfig config, RetryHandler retryHandler) {
		return new RibbonLoadBalancerContext(loadBalancer, config, retryHandler);
	}

	@Bean
	@ConditionalOnMissingBean
	public RetryHandler retryHandler(IClientConfig config) {
		return new DefaultLoadBalancerRetryHandler(config);
	}

	@Bean
	@ConditionalOnMissingBean
	public ServerIntrospector serverIntrospector() {
		return new DefaultServerIntrospector();
	}

	@PostConstruct
	public void preprocess() {
		setRibbonProperty(name, DeploymentContextBasedVipAddresses.key(), name);
	}
}

executeWithLoadBalancer方法

return lbClient(clientName)
		.executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();

executeWithLoadBalancer方法的实现代码在AbstractLoadBalancerAwareClient中:

public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) 
    throws ClientException {

    LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);

    try {
        // 负载均衡的逻辑在submit方法里面
        return command.submit(
            new ServerOperation<T>() {
                @Override
                public Observable<T> call(Server server) {
                    URI finalUri = reconstructURIWithServer(server, request.getUri());
                    S requestForServer = (S) request.replaceUri(finalUri);
                    try {
                        // 调用FeignLoadBalancer的execute方法
                        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);
        }
    }
    
}

command.submit方法:

public Observable<T> submit(final ServerOperation<T> operation) {
    final ExecutionInfoContext context = new ExecutionInfoContext();

    final int maxRetrysSame = retryHandler.getMaxRetriesOnSameServer();
    final int maxRetrysNext = retryHandler.getMaxRetriesOnNextServer();

    // Use the load balancer
    Observable<T> o = 
            // 1. selectServer方法选择一个可用的服务server
            (server == null ? selectServer() : Observable.just(server))
            .concatMap(new Func1<Server, Observable<T>>() {
                @Override
                // Called for each server being selected
                public Observable<T> call(Server server) {
                    context.setServer(server);
                    final ServerStats stats = loadBalancerContext.getServerStats(server);

                    // Called for each attempt and retry
                    Observable<T> o = Observable
                            .just(server)
                            .concatMap(new Func1<Server, Observable<T>>() {
                                @Override
                                public Observable<T> call(final Server server) {
                                    context.incAttemptCount();
                                    loadBalancerContext.noteOpenConnection(stats);

                                    if (listenerInvoker != null) {
                                        try {
                                            listenerInvoker.onStartWithServer(context.toExecutionInfo());
                                        } catch (AbortExecutionException e) {
                                            return Observable.error(e);
                                        }
                                    }

                                    final Stopwatch tracer = loadBalancerContext.getExecuteTracer().start();

                                    // 2. 调用FeignLoadBalancer的execute方法
                                    return operation.call(server).doOnEach(new Observer<T>() {
                                        private T entity;
                                        @Override
                                        public void onCompleted() {
                                            recordStats(tracer, stats, entity, null);
                                        }

                                        @Override
                                        public void onError(Throwable e) {
                                            recordStats(tracer, stats, null, e);
                                            if (listenerInvoker != null) {
                                                listenerInvoker
                                                    .onExceptionWithServer(e, context.toExecutionInfo());
                                            }
                                        }

                                        @Override
                                        public void onNext(T entity) {
                                            this.entity = entity;
                                            if (listenerInvoker != null) {
                                                listenerInvoker
                                                    .onExecutionSuccess(entity, context.toExecutionInfo());
                                            }
                                        }                            

                                        private void recordStats(
                                            	Stopwatch tracer, ServerStats stats,
                                            	Object entity, Throwable exception) {
                                            tracer.stop();
                                            loadBalancerContext.noteRequestCompletion(
                                                stats, entity, exception,
                                                tracer.getDuration(TimeUnit.MILLISECONDS),
                                                retryHandler);
                                        }
                                    });
                                }
                            });

                    // 给Observable设置重试策略
                    if (maxRetrysSame > 0) 
                        o = o.retry(retryPolicy(maxRetrysSame, true));
                    return o;
                }
            });

    // 给Observable设置重试策略
    if (maxRetrysNext > 0 && server == null) 
        o = o.retry(retryPolicy(maxRetrysNext, false));

    // 异常处理
    return o.onErrorResumeNext(new Func1<Throwable, Observable<T>>() {
        @Override
        public Observable<T> call(Throwable e) {
            if (context.getAttemptCount() > 0) {
                if (maxRetrysNext > 0 && context.getServerAttemptCount() == (maxRetrysNext + 1)) {
                    e = new ClientException(ClientException.ErrorType.NUMBEROF_RETRIES_NEXTSERVER_EXCEEDED,
                            "Number of retries on next server exceeded max " + maxRetrysNext
                            + " retries, while making a call for: " + context.getServer(), e);
                } else if (maxRetrysSame > 0 && context.getAttemptCount() == (maxRetrysSame + 1)) {
                    e = new ClientException(ClientException.ErrorType.NUMBEROF_RETRIES_EXEEDED,
                            "Number of retries exceeded max " + maxRetrysSame
                            + " retries, while making a call for: " + context.getServer(), e);
                }
            }
            if (listenerInvoker != null) {
                listenerInvoker.onExecutionFailed(e, context.toFinalExecutionInfo());
            }
            return Observable.error(e);
        }
    });
}

负载均衡LB

selectServer方法里面选择一个可用的服务节点:

private Observable<Server> selectServer() {
    return Observable.create(new OnSubscribe<Server>() {
        @Override
        public void call(Subscriber<? super Server> next) {
            try {
                // 选择可用服务节点
                Server server = loadBalancerContext
                    .getServerFromLoadBalancer(loadBalancerURI, loadBalancerKey);   
                next.onNext(server);
                next.onCompleted();
            } catch (Exception e) {
                next.onError(e);
            }
        }
    });
}

loadBalancerContext.getServerFromLoadBalancer方法:

public Server getServerFromLoadBalancer(URI original, Object loadBalancerKey) throws ClientException {
    String host = null;
    int port = -1;
    if (original != null) {
        host = original.getHost();
    }
    if (original != null) {
        Pair<String, Integer> schemeAndPort = deriveSchemeAndPortFromPartialUri(original);        
        port = schemeAndPort.second();
    }

    ILoadBalancer lb = getLoadBalancer();
    if (host == null) {
        if (lb != null) {
            // 默认使用ZoneAwareLoadBalancer负载均衡器
            Server svc = lb.chooseServer(loadBalancerKey);
            if (svc == null) {
                throw new ClientException("...");
            }
            host = svc.getHost();
            if (host == null) {
                throw new ClientException("...");
            }
            return svc;
        } else {
            if (vipAddresses != null && vipAddresses.contains(",")) {
                throw new ClientException("...");
            } else if (vipAddresses != null) {
                try {
                    Pair<String,Integer> hostAndPort = deriveHostAndPortFromVipAddress(vipAddresses);
                    host = hostAndPort.first();
                    port = hostAndPort.second();
                } catch (URISyntaxException e) {
                    throw new ClientException("...");
                }
            } else {
                throw new ClientException("...");
            }
        }
    } else {
        boolean shouldInterpretAsVip = false;

        if (lb != null) {
            shouldInterpretAsVip = isVipRecognized(original.getAuthority());
        }
        if (shouldInterpretAsVip) {
            Server svc = lb.chooseServer(loadBalancerKey);
            if (svc != null){
                host = svc.getHost();
                if (host == null){
                    throw new ClientException("...");
                }
                return svc;
            } else {
                // just fall back as real DNS
            }
        } else {
            // consult LB to obtain vipAddress backed instance given full URL
            // Full URL execute request - where url!=vipAddress
        }
    }
    // end of creating final URL
    if (host == null) {
        throw new ClientException("...");
    }
    // just verify that at this point we have a full URL

    return new Server(host, port);
}

lb.chooseServer方法:

public Server chooseServer(Object key) {
    // 默认走这个分支
    if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
        logger.debug("Zone aware logic disabled or there is only one zone");
        return super.chooseServer(key);
    }
    // ...
}

// super.chooseServer(key)
public Server chooseServer(Object key) {
    if (counter == null) {
        counter = createCounter();
    }
    counter.increment();
    // 默认ZoneAvoidanceRule
    if (rule == null) {
        return null;
    } else {
        try {
            return rule.choose(key);
        } catch (Exception e) {
            return null;
        }
    }
}

rule.choose(key)方法:

public Server choose(Object key) {
    ILoadBalancer lb = getLoadBalancer();
    Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
    if (server.isPresent()) {
        return server.get();
    } else {
        return null;
    }       
}

public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
    // 获取可用的Server集
    List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
    if (eligible.size() == 0) {
        return Optional.absent();
    }
    return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
}

// 轮询算法获取下标索引
private int incrementAndGetModulo(int modulo) {
    for (;;) {
        int current = nextIndex.get();
        int next = (current + 1) % modulo;
        if (nextIndex.compareAndSet(current, next) && current < modulo)
            return current;
    }
}

发送请求

// 调用FeignLoadBalancer的execute方法
return Observable.just(
    AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));

FeignLoadBalancer的execute方法:

public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)
		throws IOException {
	Request.Options options;
    // 设置连接超时、读超时配置
	if (configOverride != null) {
		RibbonProperties override = RibbonProperties.from(configOverride);
		options = new Request.Options(override.connectTimeout(this.connectTimeout),
				override.readTimeout(this.readTimeout));
	} else {
		options = new Request.Options(this.connectTimeout, this.readTimeout);
	}
    // 使用Client发送http请求
    // 以OkHttpClient为例
	Response response = request.client().execute(request.toRequest(), options);
	return new RibbonResponse(request.getUri(), response);
}

OkHttpClient为例:

public feign.Response execute(feign.Request input, feign.Request.Options options)
    throws IOException {
  okhttp3.OkHttpClient requestScoped;
  // 设置连接超时、读超时配置
  if (delegate.connectTimeoutMillis() != options.connectTimeoutMillis()
      || delegate.readTimeoutMillis() != options.readTimeoutMillis()
      || delegate.followRedirects() != options.isFollowRedirects()) {
    requestScoped = delegate.newBuilder()
        .connectTimeout(options.connectTimeoutMillis(), TimeUnit.MILLISECONDS)
        .readTimeout(options.readTimeoutMillis(), TimeUnit.MILLISECONDS)
        .followRedirects(options.isFollowRedirects())
        .build();
  } else {
    requestScoped = delegate;
  }
  // 构建okhttp请求对象
  Request request = toOkHttpRequest(input);
  // 发送http请求接收响应
  Response response = requestScoped.newCall(request).execute();
  // 封装feign响应对象
  return toFeignResponse(response, input).toBuilder().request(input).build();
}

响应解码

CompletableFuture<Object> resultFuture = new CompletableFuture<>();
asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
    metadata.returnType(),
    elapsedTime);

handleResponse方法:

void handleResponse(CompletableFuture<Object> resultFuture,
                    String configKey,
                    Response response,
                    Type returnType,
                    long elapsedTime) {
  // copied fairly liberally from SynchronousMethodHandler
  boolean shouldClose = true;

  try {
    // 如果feign接口方法返回值类为Response则不需要解码,直接返回
    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 {
        // Ensure the response body is disconnected
        // 获取响应字节流封装到Response并返回
        final byte[] bodyData = Util.toByteArray(response.body().asInputStream());
        resultFuture.complete(response.toBuilder().body(bodyData).build());
      }
    } else if (response.status() >= 200 && response.status() < 300) {
      // void返回类型
      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) {
    resultFuture.completeExceptionally(errorReading(response.request(), response, e));
  } catch (final Exception e) {
    resultFuture.completeExceptionally(e);
  } finally {
    if (shouldClose) {
      ensureClosed(response.body());
    }
  }
}

Object decode(Response response, Type type) throws IOException {
  try {
    return decoder.decode(response, type);
  } catch (final FeignException e) {
    throw e;
  } catch (final RuntimeException e) {
    throw new DecodeException(response.status(), e.getMessage(), response.request(), e);
  }
}

Decoder接口

public interface Decoder {

  Object decode(Response response, Type type) throws IOException, DecodeException, FeignException;
}

Decoder实现类

  • OptionalDecoder - 处理Optional类型返回值
  • ResponseEntityDecoder - Decoder adds compatibility for Spring MVC’s ResponseEntity to any other decoder via composition
  • SpringDecoder - 使用HttpMessageConverter做解码
  • StringDecoder - 处理String类型返回值

默认使用FeignClientsConfiguration装配:

@Configuration(proxyBeanMethods = false)
public class FeignClientsConfiguration {

	@Autowired
	private ObjectFactory<HttpMessageConverters> messageConverters;

	@Autowired(required = false)
	private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();

	@Autowired(required = false)
	private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();

	@Autowired(required = false)
	private Logger logger;

	@Autowired(required = false)
	private SpringDataWebProperties springDataWebProperties;

    /* 解码器 */
	@Bean
	@ConditionalOnMissingBean
	public Decoder feignDecoder() {
		return new OptionalDecoder(
				new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
	}

    /* 编码器 */
	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
	public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
		return springEncoder(formWriterProvider);
	}

    /* 编码器 */
	@Bean
	@ConditionalOnClass(name = "org.springframework.data.domain.Pageable")
	@ConditionalOnMissingBean
	public Encoder feignEncoderPageable(
			ObjectProvider<AbstractFormWriter> formWriterProvider) {
		PageableSpringEncoder encoder = new PageableSpringEncoder(
				springEncoder(formWriterProvider));

		if (springDataWebProperties != null) {
			encoder.setPageParameter(
					springDataWebProperties.getPageable().getPageParameter());
			encoder.setSizeParameter(
					springDataWebProperties.getPageable().getSizeParameter());
			encoder.setSortParameter(
					springDataWebProperties.getSort().getSortParameter());
		}
		return encoder;
	}

	@Bean
	@ConditionalOnMissingBean
	public Contract feignContract(ConversionService feignConversionService) {
		return new SpringMvcContract(this.parameterProcessors, feignConversionService);
	}

	@Bean
	public FormattingConversionService feignConversionService() {
		FormattingConversionService conversionService = new DefaultFormattingConversionService();
		for (FeignFormatterRegistrar feignFormatterRegistrar : this.feignFormatterRegistrars) {
			feignFormatterRegistrar.registerFormatters(conversionService);
		}
		return conversionService;
	}

	@Bean
	@ConditionalOnMissingBean
	public Retryer feignRetryer() {
		return Retryer.NEVER_RETRY;
	}

	@Bean
	@Scope("prototype")
	@ConditionalOnMissingBean
	public Feign.Builder feignBuilder(Retryer retryer) {
		return Feign.builder().retryer(retryer);
	}

	@Bean
	@ConditionalOnMissingBean(FeignLoggerFactory.class)
	public FeignLoggerFactory feignLoggerFactory() {
		return new DefaultFeignLoggerFactory(this.logger);
	}

	@Bean
	@ConditionalOnClass(name = "org.springframework.data.domain.Page")
	public Module pageJacksonModule() {
		return new PageJacksonModule();
	}

	@Bean
	@ConditionalOnClass(name = "org.springframework.data.domain.Page")
	public Module sortModule() {
		return new SortJacksonModule();
	}

	@Bean
	@ConditionalOnMissingBean(FeignClientConfigurer.class)
	public FeignClientConfigurer feignClientConfigurer() {
		return new FeignClientConfigurer() {
		};
	}

	private Encoder springEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
		AbstractFormWriter formWriter = formWriterProvider.getIfAvailable();

		if (formWriter != null) {
			return new SpringEncoder(new SpringPojoFormEncoder(formWriter),
					this.messageConverters);
		} else {
			return new SpringEncoder(new SpringFormEncoder(), this.messageConverters);
		}
	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
	protected static class HystrixFeignConfiguration {

		@Bean
		@Scope("prototype")
		@ConditionalOnMissingBean
		@ConditionalOnProperty(name = "feign.hystrix.enabled")
		public Feign.Builder feignHystrixBuilder() {
			return HystrixFeign.builder();
		}

	}

	private class SpringPojoFormEncoder extends SpringFormEncoder {

		SpringPojoFormEncoder(AbstractFormWriter formWriter) {
			super();

			MultipartFormContentProcessor processor = (MultipartFormContentProcessor) getContentProcessor(
					MULTIPART);
			processor.addFirstWriter(formWriter);
		}
	}
}

核心的解码逻辑在SpringDecoder中。

SpringDecoder类

public class SpringDecoder implements Decoder {

	private ObjectFactory<HttpMessageConverters> messageConverters;

	public SpringDecoder(ObjectFactory<HttpMessageConverters> messageConverters) {
		this.messageConverters = messageConverters;
	}

	@Override
	public Object decode(final Response response, Type type)
			throws IOException, FeignException {
		if (type instanceof Class || type instanceof ParameterizedType
				|| type instanceof WildcardType) {
			HttpMessageConverterExtractor<?> extractor = new HttpMessageConverterExtractor(
					type, this.messageConverters.getObject().getConverters());

            // 解码
			return extractor.extractData(new FeignResponseAdapter(response));
		}
		throw new DecodeException(response.status(),
				"type is not an instance of Class or ParameterizedType: " + type,
				response.request());
	}
}

解码:

public T extractData(ClientHttpResponse response) throws IOException {
	MessageBodyClientHttpResponseWrapper responseWrapper = 
        new MessageBodyClientHttpResponseWrapper(response);
	MediaType contentType = getContentType(responseWrapper);

	try {
        // 遍历查找适用的MessageConverter进行解码
		for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
            // 泛型
			if (messageConverter instanceof GenericHttpMessageConverter) {
				GenericHttpMessageConverter<?> genericMessageConverter =
						(GenericHttpMessageConverter<?>) messageConverter;
				if (genericMessageConverter.canRead(this.responseType, null, contentType)) {
					return (T) genericMessageConverter.read(this.responseType, null, responseWrapper);
				}
			}
            // 普通类型
			if (this.responseClass != null) {
				if (messageConverter.canRead(this.responseClass, contentType)) {
					return (T) messageConverter.read((Class) this.responseClass, responseWrapper);
				}
			}
		}
	} catch (IOException | HttpMessageNotReadableException ex) {
		throw new RestClientException("Error while extracting response for type", ex);
	}

	throw new UnknownContentTypeException(this.responseType, contentType,
			response.getRawStatusCode(), response.getStatusText(), response.getHeaders(),
			getResponseBody(response));
}

小结

至此,我们大致了解了feign client的执行流程,在后续的文章中,将进一步分析feign服务发现、负载均衡的实现方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值