一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情
图解+源码讲解代理对象 ReflectiveFeign 分析
感激每一个新的挑战,因为它会锻造你的意志和品格
feign 相关文章
图解+源码讲解 Feign 如何将客户端注入到容器中
图解+源码讲解动态代理获取 FeignClient 代理对象
图解+源码讲解代理对象 ReflectiveFeign 分析
图解+源码讲解 Feign 如何选取指定服务
图解+源码讲解 Feign 请求的流程
ribbon 相关文章
图解+源码讲解 Ribbon 如何获取注册中心的实例
图解+源码讲解 Ribbon 原理初探
图解+源码讲解 Ribbon 服务列表更新
图解+源码讲解 Ribbon 服务选择原理
Ribbon 原理初探
eureka 相关文章
eureka-server 项目结构分析
图解+源码讲解 Eureka Server 启动流程分析
图解+源码讲解 Eureka Client 启动流程分析
图解+源码讲解 Eureka Server 注册表缓存逻辑
图解+源码讲解 Eureka Client 拉取注册表流程
图解+源码讲解 Eureka Client 服务注册流程
图解+源码讲解 Eureka Client 心跳机制流程
图解+源码讲解 Eureka Client 下线流程分析
图解+源码讲解 Eureka Server 服务剔除逻辑
图解+源码讲解 Eureka Server 集群注册表同步机制
ReflectiveFeign#invoke
其实一涉及到动态代理的话那么就会涉及到方法调用,那么方法调用走的一定是invoke方法,那我们就看看看 ReflectiveFeign 方法是怎么处理 invoke 的
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 上面省略了一些方法,那些都是排除一些基础的方法的比如,equals、hashCode等
// 直接看这个方法
return dispatch.get(method).invoke(args);
}
这里面的 Map<Method, MethodHandler> dispatch 就是在创建动态代理的时候进行赋值的,里面创建好的处理方法,之后进行这个方法的调用也就是GoodsClient#goods方法的调用
再看一下invoke方法,点进去一看是一个接口那我们应该走的是 SynchronousMethodHandler 这个类实现的invoke 方法,因为我们 dispatch 里面存放的就是 SynchronousMethodHandler 上图显示的接口就是它
SynchronousMethodHandler#invoke
@Override
public Object invoke(Object[] argv) throws Throwable {
// 根据参数创建的请求模板操作
// GET /good/getGoods HTTP/1.1 Binary data
RequestTemplate template = buildTemplateFromArgs.create(argv);
// 重试器
Retryer retryer = this.retryer.clone();
// 死循环
while (true) {
// 省略了一些没有用的代码
// 其实这里我就觉得是真正的执行并且解码的操作
return executeAndDecode(template);
}
执行并且解码 executeAndDecode
执行请求操作,进行了请求之前的路径处理等操作 http://GOODS-APPLICATION/good/getGoods,利用客户端进行 execute 操作
Object executeAndDecode(RequestTemplate template) throws Throwable {
// http://GOODS-APPLICATION/good/getGoods,进行了请求之前的路径处理等操作
Request request = targetRequest(template);
// 响应结果
Response response;
try {
response = client.execute(request, options);
}
}
这个客户端就是 LoadBalancerFeignClient 客户端,这个客户端里面还有一个负载均衡工厂,那我们就去负载均衡 LoadBalancerFeignClient 看看 execue 方法
LoadBalancerFeignClient#execue
@Override
public Response execute(Request request, Request.Options options) throws IOException {
// http://GOODS-APPLICATION/good/getGoods 请求路径
URI asUri = URI.create(request.url());
// GOODS-APPLICATION 注册中心的实例名字
String clientName = asUri.getHost();
// http:///good/getGoods 去除 GOODS-APPLICATION 路径
URI uriWithoutHost = cleanUrl(request.url(), clientName);
// 创建Feign负载均衡器ribbonRequest请求
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer
.RibbonRequest(this.delegate, request, uriWithoutHost);
// 根据名字获取客户端配置信息,这里面做了很多操作,下面会讲解
IClientConfig requestConfig = getClientConfig(options, clientName);
//创建一个负载均衡客户端,之后执行操作
return lbClient(clientName)
.executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
}
获取客户端配置 getClientConfig(options, clientName)
IClientConfig getClientConfig(Request.Options options, String clientName) {
IClientConfig requestConfig;
if (options == DEFAULT_OPTIONS) {
requestConfig = this.clientFactory.getClientConfig(clientName);
}
else {
requestConfig = new FeignOptionsClientConfig(options);
}
return requestConfig;
}
这个方法里面加载了很多 Ribbon 的配置类,比如负载均衡器、如何拉取的客户端、ping规则等等
获取负载均衡客户端 lbClient(clientName)
这个 lbClientFactory 是 CachingSpringLoadBalancerFactory,之前初始化好的这个工厂
private FeignLoadBalancer lbClient(String clientName) {
// 创建负载均衡器
return this.lbClientFactory.create(clientName);
}
CachingSpringLoadBalancerFactory 里面的 create 方法
public FeignLoadBalancer create(String clientName) {
// 第一次的时候这个负载均衡器是null,如果不是第一的话那么就从缓存中获取这个负载均衡器
FeignLoadBalancer client = this.cache.get(clientName);
if (client != null) {
return client;
}
// 第一次走这个里
IClientConfig config = this.factory.getClientConfig(clientName);
// 负载均衡器是 DynamicServerListLoadBalancer,还有一些其他的信息比如服务列表,
// 拉取策略 服务选择策略什么都在获取的负载均衡器中
ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
ServerIntrospector serverIntrospector = this.factory.getInstance(clientName,
ServerIntrospector.class);
// loadBalancedRetryFactory 是空的,所以创建一个新的 FeignLoadBalancer,通过配置
// 负载均衡器等
client = this.loadBalancedRetryFactory != null
? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
this.loadBalancedRetryFactory)
: new FeignLoadBalancer(lb, config, serverIntrospector);
// 将获取的负载均衡器放入缓存中,key是服务名字 GOODS-APPLICATION,
// value是负载均衡器 FeignLoadBalancer
this.cache.put(clientName, client);
return client;
}
获取的负载均衡器里面的信息 ILoadBalancer,一看就是 ribbon里面的信息,这就说明了feign是通过 ribbon 进行负载均衡的
通过负载均衡客户端进行请求 lbClient.executeWithLoadBalancer
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig)
// 创建负载均衡指令
LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);
// 提交一个任务操作
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();
}
小结
- 调用 ReflectiveFeign 的 invoke 方法
- 封装 Request 请求模板
- 加载客户端配置,里面初始化了一些Ribbon的配置,比如拉取注册表,负载均衡器、ping规则、服务选择规则
- 创建 LoadBalancerCommand 指令进行请求执行