前言
经过前三个章节的源码阅读,对Feign中的组件已经基本熟悉,接下来就要看一下Feign动态代理的执行流程。重点看一下Feign是如何在运行时与Ribbon做结合,在何时将URL中的serviceName通过负载均衡转换为ip:port。
一、ReflectiveFeign.FeignInvocationHandler
回顾一下第二章,创建JDK动态代理的时候,InvocationHandler的实现类FeignInvocationHandler是由feign.InvocationHandlerFactory.Default创建的。
static final class Default implements InvocationHandlerFactory {
// target:HardCodedTarget(FeignClientFactoryBean#getTarget里new的一个对象,[type=SpecificationStockClient, name=trade-service, url=http://trade-service])
// dispatch:目标方法和实际方法处理器的一个mapping关系
// 通过变量名可以看出FeignInvocationHandler并不实际执行代理逻辑,而是根据method分发给不同的MethodHandler处理
// 通过method实例可以直接找到MethodHandler,最后通过MethodHandler的invoke方法,实际执行代理逻辑
@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}
}
接下来直接进入FeignInvocationHandler.invoke方法
static class FeignInvocationHandler implements InvocationHandler {
private final Target target;
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、toString等Object类方法的处理...
// 根据方法找到方法实际的Handler
MethodHandler handler = dispatch.get(method);
// 执行SynchronousMethodHandler的invoke方法
return handler.invoke(args);
}
}
二、SynchronousMethodHandler的invoke方法
@Override
public Object invoke(Object[] argv) throws Throwable {
// 1. 创建RequestTemplate
RequestTemplate template = buildTemplateFromArgs.create(argv);
// 2. 尝试从方法参数中获取Options
// 如果为空,则使用创建SynchronousMethodHandler时注入的Options
Options options = findOptions(argv);
// clone一个重试处理类
Retryer retryer = this.retryer.clone();
while (true) {
try {
// 3. 执行
return executeAndDecode(template, options);
} catch (RetryableException e) {
// 是否可以重试,如果可以则继续执行executeAndDecode
try {
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
// 解析异常重新抛出
}
continue;
}
}
}
1、创建RequestTemplate
BuildTemplateByResolvingArgs是ReflectiveFeign.ParseHandlersByName#apply方法创建的类,主要是通过方法入参(Object[] argv)和HardCodeTarget和MethodMetadata(由SpringMvcContract解析出来的Method抽象),构建URI。 比如把/getStockById/{mpId}解析为/getStockById/2,这里不详细分析了,就是一段复杂的解析和组装方法。
2、findOptions尝试从方法参数中获取Options
如果参数中有个一个参数是Options,则使用第一个,否则使用默认注入的
Options findOptions(Object[] argv) {
if (argv == null || argv.length == 0) {
return this.options;
}
return Stream.of(argv)
.filter(Options.class::isInstance)
.map(Options.class::cast)
.findFirst()
.orElse(this.options);
}
3、executeAndDecode
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
// 1. 执行所有RequestInterceptor,最后执行Target的apply方法获得Request
Request request = targetRequest(template);
// 2. 执行请求
Response response = client.execute(request, options);
response = response.toBuilder()
.request(request)
.requestTemplate(template)
.build();
// 3. 结果处理,最终还是使用FeignClientsConfiguration#feignDecoder里配置的HttpMessageConverters来解析返回结果
CompletableFuture<Object> resultFuture = new CompletableFuture<>();
asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
metadata.returnType(),
elapsedTime);
if (!resultFuture.isDone())
throw new IllegalStateException("Response handling not done");
return resultFuture.join();
}
三、LoadBalancerFeignClient#execute
@Override
public Response execute(Request request, Request.Options options) throws IOException {
// 创建uriWithoutHost http:///getStockByMpId/2
URI asUri = URI.create(request.url());
String clientName = asUri.getHost();
URI uriWithoutHost = cleanUrl(request.url(), clientName);
// 封装Client、Request和uriWithoutHost为RibbonRequest
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
this.delegate, request, uriWithoutHost);
// 一段古怪的逻辑,根据options是否是自动配置的options,获取IClientConfig
IClientConfig requestConfig = getClientConfig(options, clientName);
// 通过CachingSpringLoadBalancerFactory的create方法
// 获取FeignLoadBalancer继承ribbon的AbstractLoadBalancerAwareClient
FeignLoadBalancer lbClient = lbClient(clientName)
// 执行请求
return lbClient.executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
}
getClientConfig
IClientConfig getClientConfig(Request.Options options, String clientName) {
IClientConfig requestConfig;
if (options == DEFAULT_OPTIONS) {
// 如果使用默认配置(FeignRibbonClientAutoConfiguration#feignRequestOptions全局容器默认注入的)
// 整个IClientConfig取Ribbon的DefaultClientConfigImpl,也就是说超时时间啥的配置都是走Ribbon配置
requestConfig = this.clientFactory.getClientConfig(clientName);
}
else {
// 如果Options走的是Feign自己的配置,那么整个IClientConfig取DefaultClientConfigImpl的默认配置,FeignOptionsClientConfig只是把超时时间做了特殊配置
requestConfig = new FeignOptionsClientConfig(options);
}
return requestConfig;
}
lbClient(clientName)获取FeignLoadBalancer
private FeignLoadBalancer lbClient(String clientName) {
return this.lbClientFactory.create(clientName);
}
通过CachingSpringLoadBalancerFactory.create(clientName)创建FeignLoadBalancer,这里拿到了Ribbon中ILoadBalancer的实现,集成了Ribbon
public class CachingSpringLoadBalancerFactory {
// Ribbon命名容器工厂
protected final SpringClientFactory factory;
// 缓存clientName -> FeignLoadBalancer
private volatile Map<String, FeignLoadBalancer> cache = new ConcurrentReferenceHashMap<>();
public FeignLoadBalancer create(String clientName) {
FeignLoadBalancer client = this.cache.get(clientName);
if (client != null) {
return client;
}
// 1. 获取Ribbon中的各种组件的实现
IClientConfig config = this.factory.getClientConfig(clientName);
ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
ServerIntrospector serverIntrospector = this.factory.getInstance(clientName,
ServerIntrospector.class);
// 2. 封装为FeignLoadBalancer,继承ribbon的AbstractLoadBalancerAwareClient
client = new FeignLoadBalancer(lb, config, serverIntrospector);
this.cache.put(clientName, client);
return client;
}
}
FeignLoadBalancer.executeWithLoadBalancer
这里开始都是基于rxjava的响应式编程,这里按照直观的顺序介绍负载均衡的流程。command.submit创建了被观察者Observable,toBlocking().single()触发了subcribe。
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
// 1 构建LoadBalancerCommand
// 封装URI(http:///getStockByMpId/1)和自己(FeignLoadBalancer)到LoadBalancerCommand里
LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);
// 2 执行LoadBalancerCommand创建了被观察者,并
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);
return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
}
})
.toBlocking()
.single();
}
submit方法关注selectServer()返回一个Observable,等待被toBlocking().single()里的subscribe触发
public Observable<T> submit(final ServerOperation<T> operation) {
// ...
Observable<T> o =
// 1. 选择server
(server == null ? selectServer() : Observable.just(server))
.concatMap(new Func1<Server, Observable<T>>() {
@Override
public Observable<T> call(Server server) {
Observable<T> o = Observable
.just(server)
.concatMap(new Func1<Server, Observable<T>>() {
@Override
public Observable<T> call(final Server server) {
// 2. server选择完了,执行传入operation的call方法
return operation.call(server)
.doOnEach(new Observer<T>() {
...
});
}
});
}
});
...
return o;
}
1、selectServer选择Server
调用LoadBalancerContext里的ILoadBalancer的chooseServer,chooseServer调用IRule的choose方法,这都是Ribbon的实现。
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);
}
}
});
}
2、ServerOperation.call
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
// 1 构建LoadBalancerCommand 忽略
LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);
// 2 执行LoadBalancerCommand 忽略
return command.submit(
// 看这里
new ServerOperation<T>() {
@Override
public Observable<T> call(Server server) {
// 1 LoadBalancerContext#reconstructURIWithServer重构URI,完全Ribbon实现
URI finalUri = reconstructURIWithServer(server, request.getUri());
// 2 通过clone方法复制一个RibbonRequest
S requestForServer = (S) request.replaceUri(finalUri);
// 3 执行AbstractLoadBalancerAwareClient.this.execute
return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
}
})
.toBlocking()
.single();
}
- replaceUri:clone复制FeignLoadBalancer.RibbonRequest,用传入的uri更新RibbonRequest的uri
public ClientRequest replaceUri(URI newURI) {
ClientRequest req;
try {
req = (ClientRequest)this.clone();
} catch (CloneNotSupportedException var4) {
req = new ClientRequest(this);
}
req.uri = newURI;
return req;
}
3、FeignLoadBalancer.execute(FeignLoadBalancer.RibbonRequest, IClientConfig)
这时RibbonRequest里的URI已经是负载均衡之后的ip:port形式了,接下来只要执行http请求
@Override
public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)
throws IOException {
// 一段再次构造Options的逻辑判断,configOverride非空,取得就是configOverride里的超时时间
Request.Options options = ...
// feign.Client.Default#execute
Response response = request.client().execute(request.toRequest(), options);
return new RibbonResponse(request.getUri(), response);
}
- feign.Client.Default#execute
@Override
public Response execute(Request request, Options options) throws IOException {
// 构造java.net.HttpURLConnection,用Options设置超时时间,并执行http请求
HttpURLConnection connection = convertAndSend(request, options);
// 构造Response
return convertResponse(connection, request);
}
总结
- ReflectiveFeign.FeignInvocationHandler:JDK的InvocationHandler的实现类,动态代理执行入口,根据Method找到MethodHandler,调用SynchronousMethodHandler的invoke方法。
- SynchronousMethodHandler的invoke方法:调用FeignLoadBalancer。
- FeignLoadBalancer:继承Ribbon的AbstractLoadBalancerAwareClient,实现LoadBalancerContext和IClient接口,有负载均衡、执行请求的能力。
- Ribbon相关:
- 用LoadBalancerContext里的ILoadBalancer的chooseServer,chooseServer调用IRule的choose方法,获取Server
- LoadBalancerContext#reconstructURIWithServer重构URI