前文《OpenFeign源码01 接口扫描和创建代理》中分析了创建feign代理的流程,本文将从代理ReflectiveFeign.FeignInvocationHandler(实现了InvocationHandler接口)入手,分析feign client的执行流程:
- SynchronousMethodHandler类的invoke方法
- 执行拦截器的逻辑并获取feign Request
- LoadBalancer负载均衡逻辑
- 发送请求
- 响应解码
回顾创建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;
}
}
流程:
- 执行拦截器的逻辑并获取Request
- 使用Client执行http请求,这里是LoadBalancerFeignClient对象
- 响应解码
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服务发现、负载均衡的实现方式。