Feign源码阅读(四)Feign动态代理执行流程解析

2,548 阅读4分钟

前言

  经过前三个章节的源码阅读,对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