Skip to main content

OpenFeign执行流程(三):从接口声明到底层网络通信

接下来我们将探索 OpenFeign 的执行流程,深入了解每个关键步骤背后的原理。从接口的声明到实际 HTTP 请求的发送,我们将跟随 OpenFeign 的脚步,揭示它是如何将高级的服务调用抽象转化为底层的网络通信

我们需要简单构造一个FeignClient,用于请求测试

@FeignClient(name = "power-user",contextId = "power-user-UserService")
public interface UserService {
/**
* 根据用户id获取用户信息
* @param userId 用户id
* @return 用户信息
*/
@GetMapping("/getUser")
LoginUser getUser(String userId);

}

在实际执行远程调用的过程中,我们将深入invoke反射方法中

这涉及到一个工厂反射类InvocationHandlerFactory,该工厂类提供了create方法用于创建InvocationHandler

public interface InvocationHandlerFactory {

InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch);

/**
* Like {@link InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])}, except for a
* single method.
*/
interface MethodHandler {

Object invoke(Object[] argv) throws Throwable;
}
//默认的InvocationHandler工厂类
static final class Default implements InvocationHandlerFactory {

@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}
}
}

构造函数接受了一个派发器(dispatch),就是上章结尾的methodHandler

  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);
}
}
  public Object invoke(Object[] argv) throws Throwable {
//构建请求模板
RequestTemplate template = buildTemplateFromArgs.create(argv);
//根据参数 argv 查找与请求相关的选项 (Options)。选项通常包括一些配置信息,如超时时间、重试策略等。
Options options = findOptions(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
//执行逻辑
return executeAndDecode(template, options);
} catch (RetryableException e) {
try {
//检查是否可重试,如果不可重试,则抛出异常,中断while(true)
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}

在这一步,我们不再深入探讨细节,直接转向executeAndDecode(template, options)

   Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
// 创建用于发送请求的 Request 对象
Request request = targetRequest(template);

// 如果日志级别不为 NONE,记录请求信息
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}

// 发送请求并获得响应
Response response;
long start = System.nanoTime();
try {
//执行请求,内部进行了负载均衡的调用
response = client.execute(request, options);
} catch (IOException e) {
// 如果出现 IOException,在日志中记录异常信息
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
throw errorExecuting(request, e); // 抛出异常,请求执行失败
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);

// 标志是否需要关闭响应体,默认为 true
boolean shouldClose = true;
try {
// 如果日志级别不为 NONE,记录响应信息
if (logLevel != Logger.Level.NONE) {
response =
logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);
}

// 如果返回类型为 Response,返回响应对象
if (Response.class == metadata.returnType()) {
if (response.body() == null) {
return response;
}
if (response.body().length() == null ||
response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
shouldClose = false;
return response;
}
// Ensure the response body is disconnected
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
return response.toBuilder().body(bodyData).build();
}
// 如果响应状态码在 200 到 299 之间,表示请求成功
if (response.status() >= 200 && response.status() < 300) {
// 如果返回类型为 void,返回 null
if (void.class == metadata.returnType()) {
return null;
} else {
// 对响应进行解码并返回结果
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
}
}
// 如果 decode404 为 true,且响应状态码为 404,并且返回类型不为 void
else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
// 对响应进行解码并返回结果
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
} else {
// 如果响应状态码不在 200 到 299 之间,抛出异常
throw errorDecoder.decode(metadata.configKey(), response);
}
} catch (IOException e) {
// 如果出现 IOException,在日志中记录异常信息
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
}
throw errorReading(request, response, e); // 抛出异常,读取响应失败
} finally {
// 根据 shouldClose 标志决定是否关闭响应体
if (shouldClose) {
ensureClosed(response.body());
}
}
}

targetRequest(template) 中,拦截器的加载发挥着关键作用。在实际执行之前,所有拦截器都会对 template 进行加工,这为定制化请求参数、修改请求头等提供了灵活性(例如链路追踪,i18n)。如果需要调整拦截器的执行顺序,可以使用 @Order 字段,这个字段本质上也是通过 Spring 获取到的,进一步增强了对拦截器执行顺序的控制

  Request targetRequest(RequestTemplate template) {
for (RequestInterceptor interceptor : requestInterceptors) {
interceptor.apply(template);
}
return target.apply(template);
}

关于Feign的默认拦截器,我们将在下一篇文章中进行详细梳理。接下来,我们将深入探讨execute方法的源码

  @Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
//获取url
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);
//lbClient(clientName) 内部有缓存机制拿到对应的负载均衡策略类,执行executeWithLoadBalancer
return lbClient(clientName)
.executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
}
catch (ClientException e) {
IOException io = findIOException(e);
if (io != null) {
throw io;
}
throw new RuntimeException(e);
}
}

lbClient(clientName)内部创建了一个FeignLoadBalancer


public FeignLoadBalancer create(String clientName) {
// 从缓存中获取已存在的 FeignLoadBalancer 客户端
FeignLoadBalancer client = this.cache.get(clientName);
if (client != null) {
return client; // 如果已存在,直接返回
}
// protected final SpringClientFactory factory;
//该factory是进行初始化时给设置的,他内部也是继承了NamedContextFactory ,所以这里也是环境隔离
// 获取指定客户端名称的配置
IClientConfig config = this.factory.getClientConfig(clientName);

// 获取指定客户端名称的负载均衡器
ILoadBalancer lb = this.factory.getLoadBalancer(clientName);

// 获取指定客户端名称的 ServerIntrospector
ServerIntrospector serverIntrospector = this.factory.getInstance(clientName,
ServerIntrospector.class);

// 如果 loadBalancedRetryFactory 不为 null,使用 RetryableFeignLoadBalancer 创建客户端
client = this.loadBalancedRetryFactory != null
? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
this.loadBalancedRetryFactory)
: new FeignLoadBalancer(lb, config, serverIntrospector);

// 将创建的客户端放入缓存
this.cache.put(clientName, client);

// 返回创建的客户端
return client;
}

在获取到 FeignLoadBalancer 负载均衡器后,通过调用 executeWithLoadBalancer 方法,OpenFeign 的执行流程就在此刻完成。这一步骤涵盖了负载均衡、远程服务调用等核心操作,是整个 OpenFeign 的关键执行点