图解+源码讲解代理对象 ReflectiveFeign 分析

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情

图解+源码讲解代理对象 ReflectiveFeign 分析

感激每一个新的挑战,因为它会锻造你的意志和品格

相关文章
图解+源码讲解 Feign 如何将客户端注入到容器中
图解+源码讲解动态代理获取 FeignClient 代理对象

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方法的调用
image.png
    再看一下invoke方法,点进去一看是一个接口那我们应该走的是 SynchronousMethodHandler 这个类实现的invoke 方法,因为我们 dispatch 里面存放的就是 SynchronousMethodHandler 上图显示的接口就是它
image.png

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 方法
image.png

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规则等等
image.png

获取负载均衡客户端 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 进行负载均衡的
image.png

通过负载均衡客户端进行请求 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();
}
复制代码

小结

  1. 调用 ReflectiveFeign 的 invoke 方法
  2. 封装 Request 请求模板
  3. 加载客户端配置,里面初始化了一些Ribbon的配置,比如拉取注册表,负载均衡器、ping规则、服务选择规则
  4. 创建 LoadBalancerCommand 指令进行请求执行

猜你喜欢

转载自juejin.im/post/7088119282101387271