Retrofit 源码深度解析-(3)Invoke

2.4 ServiceMethod#invoke

2.4.1 时序图

invoke的第一步,是执行CallAdapted#invoke,通过上面的UML图分析,可以知道在HttpServiceMethod实现了ServiceMethodinvoke

@Override
final @Nullable ReturnT invoke(Object[] args) {
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  return adapt(call, args);
}

首先 new了一个OkHttpCall,随后转到了ServiceMethod#adapt方法。

进入adapt

@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
  return callAdapter.adapt(call);
}

内部转到了CallAdapter处理请求。

从上面的流程,可以看到,作为继承自ServiceMethod的CallAdapted来说,主要工作有两个:1)构建OkHttpCall,2)将OkHttpCall实例传入适配器进行处理。

同时,由CallAdapted的处理思路以及命名,也大概明白CallAdapted属ServiceMethodCallAdapter的桥梁。

好了,现在来到CallAdapter

2.4.2 CallAdapter

单单看CallAdapter的定义:

/**
* 将响应类型为R的Call调整为T的类型
*/
public interface CallAdapter<R, T> {
  /**
  * 返回此适配器在将HTTP响应主体转换为Java对象时使用的值类型。例如,Call<Repo>的响应类型是Repo。
  	此类型用于准备传递给#adapt的调用。
  	注意:这通常与提供给此调用适配器工厂的returnType不同。
  */
  Type responseType();
  /**
  * 返回一个委托调用的T实例。
		例如,给定一个假设的实用程序Async的实例,该实例将返回一个新的Async<R>,该Async在运行时调用。
		@Override
     public <R> Async<R> adapt(final Call<R> call) {
       return Async.create(new Callable<Response<R>>() {
         @Override
         public Response<R> call() throws Exception {
           return call.execute();
         }
       });
     }
  */
  T adapt(Call<R> call);
}

可以得知,该组件是用于通过将Call\<R\>R进行转换,从而得到一个T类型的实例。而R类型,在创建CallAdapter时由工厂代码的get方法所接收。

同时responseType方法在上面parseAnnotations有讲到,是用来确定responseConvert的。

可能看注释不太能理解CallAdapter组件的存在意义,可以通过看Retroft提供的几个CallAdapter的实现类,来窥探出CallAdapter组件的职责。

image

忽略两个测试类,可以看到,Retrofit默认提供了三个实现类:DefaultCallAdapterFactory#anonymousClassBodyCallAdapterResponseCallAdapter

这两个类可能没印象了,这里回顾一下Retrofit.Build#build的代码:

// Retrofit.Build#build代码片段
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

// Platform#defaultCallAdapterFactories 方法
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
  @Nullable Executor callbackExecutor) {
  DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
  return hasJava8Types
    ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
    : singletonList(executorFactory);
}

可以看到,在Hotspot平台下,默认会有两个CallAdapterFactoryDefaultCallAdapterFactoryCompletableFutureCallAdapterFactory。而上面三个CallAdapter实现类,就是通过这两个工厂类构建出来的,接下来进行一一分析。

2.4.2.1 DefaultCallAdapterFactory#anonymousClass

由于这个工厂提供的CallAdapter是一个匿名内部类,所以为了更好的理解,这里DefaultCallAdapterFactory#get将代码贴出来

public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
  if (getRawType(returnType) != Call.class) {
    // 只支持方法返回值为Call类型的方法
    return null;
  } else if (!(returnType instanceof ParameterizedType)) {
    // 必须指定Call的形参类型 
    throw new IllegalArgumentException("Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
  } else {
    // 获取Call<String>的String类型
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType)returnType);
    // 方法是否包含@SkipCallbackExecutor注解
    final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null : this.callbackExecutor;
    
    // 创建一个匿名内部类
    return new CallAdapter<Object, Call<?>>() {
      // 如果方法返回值是Call<String> 那么这里返回的type就是String,通过这个类型 来指定responseConvert类型
      // 同时 这个类型也定义了adapt方法参数Call的形参参数类型
      public Type responseType() {
        return responseType;
      }
			
      public Call<Object> adapt(Call<Object> call) {
        // 这里的executor的设置,来源于Retrofit.Build#build时,添加的基于platform的执行器
        // 如果是Hotspot平台,则这个方法将参数的call直接返回了
        // 其实通过DefaultCallAdapterFactory#get方法的校验流程,也可以知道,当前Convert的返回值是Call类型
        return (Call)(executor == null ? call : new DefaultCallAdapterFactory.ExecutorCallbackCall(executor, call));
      }
    };
  }
}

通过get方法return之前的代码可以明确的是当前CallAdapter#adapt方法返回的是Call类型,也就需要Service方法的返回类型是Call,例如:

public interface BaiduApi {
  @GET("/")
  Call<String> get1(@Query("aaa") String args);
}

这种是支持的。同时由于adapt方法的入参既Call,所以方法直接将Call返回。(不考虑Android的平台)

可能一个CallAdapter还不能整理出规则,继续看Retrofit提供的下一个CallAdapter

2.4.2.2 BodyCallAdapter

BodyCallAdapter是由CompletableFutureCallAdapterFactory进行构建的,查看构建的代码:

// CompletableFutureCallAdapterFactory#get 代码片段
if (getRawType(returnType) != CompletableFuture.class) {
  // 只关心方法返回值为CompletableFuture类型的方法
  return null;
}

if (getRawType(innerType) != Response.class) {
  // 如果方法返回值是CompletableFuture<String或者其他具体类型> 的 返回BodyCallAdapter
  // Generic type is not Response<T>. Use it for body-only adapter.
  return new BodyCallAdapter<>(innerType);
}

通过最上面的returnType的校验,可以得知CompletableFutureCallAdapterFactory是针对方法返回值为java8的CompletableFuture类型所提供CallAdapter的。

所以继续查看BodyCallAdapter

private static final class BodyCallAdapter<R> implements CallAdapter<R, CompletableFuture<R>> {
  // 移除了responseType相关定义

  @Override
  public CompletableFuture<R> adapt(final Call<R> call) {
    // new 了一个CallCancelCompletableFuture
    CompletableFuture<R> future = new CallCancelCompletableFuture<>(call);
    // new 了一个BodyCallback
    call.enqueue(new BodyCallback(future));
    return future;
  }
}

adapt方法内部有引出了两个关键的类:CallCancelCompletableFutureBodyCallback

其中CallCancelCompletableFuture继承了CompletableFuture,定义了一个Call类型的构造函数,同时重写了cancel方法:

private static final class CallCancelCompletableFuture<T> extends CompletableFuture<T> {
 // 隐去构造函数等代码
  @Override
  public boolean cancel(boolean mayInterruptIfRunning) {
    if (mayInterruptIfRunning) {
      // 执行Call cancel
      call.cancel();
    }
    return super.cancel(mayInterruptIfRunning);
  }
}

而而BodyCallback则实现了Callback


private class BodyCallback implements Callback<R> {
  private final CompletableFuture<R> future;
  // 通过构造函数传入CompletableFuture
  public BodyCallback(CompletableFuture<R> future) {
    this.future = future;
  }

  @Override
  public void onResponse(Call<R> call, Response<R> response) {
    if (response.isSuccessful()) {
      // 成功 则调用CompletableFuture#complete
      future.complete(response.body());
    } else {
      future.completeExceptionally(new HttpException(response));
    }
  }

  @Override
  public void onFailure(Call<R> call, Throwable t) {
    // 失败调用
    future.completeExceptionally(t);
  }
}

通过上面的代码,大概明白了BodyCallAdapter组件的用处:

通过对返回值类型为CompletableFuture<Response<具体类型>>的适配。

举个例子:

@GET("/")
CompletableFuture<String> get26();

则调用方:

CompletableFuture<String> responseCompletableFuture = retrofit.create(BaiduApi.class).get26();
// 获取异步结果
String stringResponse = responseCompletableFuture.get();
// 或者 有限时间获取
responseCompletableFuture.get(1, TimeUnit.SECONDS);

可以达到发起请求为异步的效果。

2.4.2.3 ResponseCallAdapter

这个同BodyCallAdapter差不大多,区别在于ResponseCallAdapter适配的是方法返回值为CompletableFuture<Response<String>或者其他类型>BodyCallAdapter 则为其他泛型。

2.4.2.4 CallAdapter总结

通过对三款默认的CallAdapter的代码定义,以及场景分析,由此我们可以知道,CallAdapter是针对方法的具体业务返回值之上的一层包装适配。

例如,如果业务返回的对象为Data,但同时在一些特殊场景下,例如异步,则可以将结果包装成CompletableFuture<Data>,或者使用RxJava。可以达到异步和回调的效果。

这个部分同ResponseConvert有一些些许的概念冲突,因为ResponseConver的定义是将Http返回结果给转换成需要的对象,当前对象是业务对象,而CallAdapter则在业务对线之上提供一个扩展,可以以不同的方式来接入。

实际场景:异步、回调、

或者通过查看retrofit-adapters目录:

image

基本都是对现在比较主流的异步框架进行适配。

介绍完CallAdapter之后,继续回到调用流程当中。由于CallAdapter有多个实现,但其实思路都差不多,这里使用DefaultCallAdapterFactory#anonymousClass来进行流程梳理:

public Call<Object> adapt(Call<Object> call) {
 return (Call)(executor == null ? call : new DefaultCallAdapterFactory.ExecutorCallbackCall(executor, call));
}

可以看到,DefaultCallAdapterFactory#anonymousClass只是简单的将call进行返回。所以回忆一下我们的使用:

public interface BaiduApi {
    @GET("/")
    Call<String> get1(@Query("aaa") String args);
}

// 调用
Call<String> api = retrofit.create(BaiduApi.class).get1("");
// 真正执行
Response<String> stringResponse = api.execute();

所以下一个流程,就在api.execute()当中

2.5 execute

2.51 时序图

2.5.2 Retrofit2.Call

要理清Call#execute方法的内部实现,就需要先Retrofit2.Call的定义。

先看类的定义:

image

乍一看没什么特殊的,但用过okhttp的同学可能有点印象,那么,继续看看okhttp3.Call的定义:

image

可以看到,不能说是毫无关系,只能说是基本一样。实际上,Retrofit2.Call就是对okhttp3.Call的包装,在其基础之上,通过ResponseConvert将返回结果包装成对应的返回对象。

看看官方对Retrofit2.Call的定义:

An invocation of a Retrofit method that sends a request to a webserver and returns a response. Each call yields its own HTTP request and response pair. Use clone to make multiple calls with the same parameters to the same webserver; this may be used to implement polling or to retry a failed call.
Calls may be executed synchronously with execute, or asynchronously with enqueue. In either case the call can be canceled at any time with cancel. A call that is busy writing its request or reading its response may receive a IOException; this is working as designed.

对Retrofit方法的调用,该方法向web服务器发送请求并返回响应。每个调用都会产生自己的HTTP请求和响应对。使用clone()对同一个web服务器进行多次调用,使用相同的参数;这可用于实现轮询或重试失败的调用。
调用可以通过execute同步执行,也可以通过enqueue异步执行。在这两种情况下,call都可以在任何时候用cancel来取消。一个正在写请求或读取响应的调用可能会收到IOException;这是设计好的。

通过定义大概明白了Retrofit2.Call的角色:Retrofit Service方法调用的抽象。同时还得知了Retrofit2.Call的一些特性:可异步化、取消、通过clone()方法进行请求复制达到重试的机制等等。

同时,伴随着Retrofit2.Call的,还有一个特殊组件:retrofit2.Callback

image

Retrofit2.Call一样,改组件是为了适配okhttp3.Callback

image

在了解了Retrofit2.Call的定义之后,继续深入到内部实现。通过查看Retrofit2.Call的实现类:

image

2.5.2.1 OkHttpCall

不知道大家对这个类还有没有印象,在HTTPServiceMethod#invoke方法中,new了一个OkHttpCall实例:

@Override
final @Nullable ReturnT invoke(Object[] args) {
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  return adapt(call, args);
}

默认情况下,OkHttpCall就是我们调用时的Call实现,所以,通过OkHttpCall,就可以知道核心的http请求流程,retrofit是如何整合okhttp3的。

先看一下OkHttpCall的UML图:

image

可以看到,在OkhttpCall的属性当中,关键的几个属性requestFactory, args, callFactory, responseConverter,是通过构造函数传入的,分别是:构建请求参数的工厂,调用方法传入的参数,okhttpCall实例和返回结果的转换器。

接下来通过解析execute方法内部的实现,来一探究竟。

2.5.2.1.1 OkhttpCall#execute

先看一下代码:

@Override
  public Response<T> execute() throws IOException {
    okhttp3.Call call;
    
    // 一个Call只可以被调用一次,避免并发
    synchronized (this) 
      // 使用executed标志位记录执行状态
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
			// 获取到一个okhttp3.Call实例
      call = getRawCall();
    }
		// 在真正执行前,先判断是否被调用了retrofit.Call#cancel 则中断调用
		// canceled是一个被volatile修饰过的
    if (canceled) {
      call.cancel();
    }
		// 执行okhttp3.Call#execute并将返回结果转换
    return parseResponse(call.execute());
  }

可以看到,整个代码思路还是很清晰的,加锁避免重复调用,构建 okhttp3.Call实例,执行 okhttp3.Call#execute方法,转换返回数据。下面对每个关键步骤进行一一解析。

2.5.2.1.2 OkhttpCall#getRawCall

通过该方法的定义,就可以知道这个方法是返回一个原始的okhttp3.Call实例的。

private okhttp3.Call getRawCall() throws IOException {
  okhttp3.Call call = rawCall;
  if (call != null) return call;

  // 抛出上一次创建的异常,因为有可能是多次调用
  if (creationFailure != null) {
    if (creationFailure instanceof IOException) {
      throw (IOException) creationFailure;
    } else if (creationFailure instanceof RuntimeException) {
      throw (RuntimeException) creationFailure;
    } else {
      throw (Error) creationFailure;
    }
  }

  // 创建 并记录成功或者失败
  try {
    return rawCall = createRawCall();
  } catch (RuntimeException | Error | IOException e) {
    // 这个方法内部针对一些致命错误进行了抛出 例如虚拟机异常等等
    throwIfFatal(e); // 不要给creationFailure分配致命错误。
    creationFailure = e;
    throw e;
  }
}

private okhttp3.Call createRawCall() throws IOException {
  okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

首先判断了属性creationFailure是否不为空,如果不为空则抛出。这个判断是为了避免在重复调用Call时,上一次失败的情况下,就直接抛出了。

随后,转入createRawCall方法真正执行创建。熟悉okhttp的同学应该对这个代码比较熟悉,使用facotry 传入okhttp3.Request后new 一个call

其中最核心的,最需要关注的,是RequestFactory#create

好了,还记得之前在ServiceMethod#parseAnnotations方法,构造出来的RequestFactory吗?现在就用上了。

okhttp3.Request create(Object[] args) throws IOException {
  
  ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

  int argumentCount = args.length;
  if (argumentCount != handlers.length) {
    // 抛出异常 参数数量匹配不上
  }
  
  // 构建RequestBuilder实例
  RequestBuilder requestBuilder =
    new RequestBuilder(
    httpMethod,
    baseUrl,
    relativeUrl,
    headers,
    contentType,
    hasBody,
    isFormEncoded,
    isMultipart);

  List<Object> argumentList = new ArrayList<>(argumentCount);
  for (int p = 0; p < argumentCount; p++) {
    argumentList.add(args[p]);
    // 迭代handlers,调用对应的apply方法
    handlers[p].apply(requestBuilder, args[p]);
  }
  // 得到Request.Builder实例,打上tag,再调用build方法构建Request
  return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}

RequestFactory#create方法的目的,是创建一个okhttp3.Request实例。

内部先是构建了一个RequestBuilder实例,然后通过RequestBuilder#get得到okhttpRequest.Builder,再通过Request.Builder#build得到Request实例,

RequestFactory#create -> RequestBuilder#get -> Request.Builder#build

接下来一个个详细解析。

2.5.2.1.3 RequestBuilder

在之前讲ParameterHandler的时候,就提到过RequestBuilder,所有的ParameterHandler#apply方法,都是将对应参数以其能转换的方式add到RequestBuilder当中。

RequestBuilder的作用,是构造出一个okhttpRequest.Builder,为build Request做准备。先来看看RequestBuilder的UML图:

image

RequestBuilder方法的定义看到了那些熟悉的方法,addHeaderaddPart等等。

由于对应的方法都在ParameterHandler提到过,所以就不再赘述了,直接看最核心的get方法:

Request.Builder get() {
  HttpUrl url;
  // 如果不为空,this.urlBuilder是在第一次调用addQueryParam方法的时候构建的
  HttpUrl.Builder urlBuilder = this.urlBuilder;
  if (urlBuilder != null) {
    url = urlBuilder.build();
  } else {
    url = baseUrl.resolve(relativeUrl);
    if (url == null) {
      // 解析relativeUrl失败
      throw new IllegalArgumentException( "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
    }
  }
	
  RequestBody body = this.body;
  if (body == null) {
    // Try to pull from one of the builders.
    if (formBuilder != null) {
      // 表单body
      body = formBuilder.build();
    } else if (multipartBuilder != null) {
      // multipart body
      body = multipartBuilder.build();
    } else if (hasBody) {
      // 如果http方法的定义是有body的,但是没穿这个参数,就构建一个空的body
      body = RequestBody.create(null, new byte[0]);
    }
  }

  MediaType contentType = this.contentType;
  if (contentType != null) {
    if (body != null) {
    // 使用设置的contentType 覆盖掉RequestBody的Content-Type返回值 ContentTypeOverridingRequestBody其实就是一个代理类
      body = new ContentTypeOverridingRequestBody(body, contentType);
    } else {
      // body为空的话 就只添加hander了
      headersBuilder.add("Content-Type", contentType.toString());
    }
  }
  // 继续添加url header method body 然后返回RequestBuilder实例
  return requestBuilder.url(url).headers(headersBuilder.build()).method(method, body);
}

get方法,整体看下来基本分为校验和通过将当前builder的参数构建出RequestBuilder。在执行到这一步时,Service方法对应的参数都已经被转换成离构建最终的Request之前一步的中间态了。

所以接下来,就是使用中间态的数据,真正构建Request,也就是okhttp3.Request.Builder#build。不过这里已经到okhttp的范畴了,等以后写okhttp的源码解析时,可以再聊聊。

至此,调用okhttp的最重要的Request已经构建成功。回到retrofit.Call#execute,接下来的步骤就是调用okhttp3.Call#execute,然后来到最后一个关键组件:ResponseConverter

2.5.2.1.4 Retrofit.Call#parseResponse

直接看代码:

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
  ResponseBody rawBody = rawResponse.body();

  // 构建一个新的Response 因为上面已经拿着原始的body了 这么做可以只关注状态码等等信息
  rawResponse =
    rawResponse
    .newBuilder()
    .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
    .build();

  int code = rawResponse.code();
  if (code < 200 || code >= 300) {
    try {
      // Buffer the entire body to avoid future I/O.
      // 缓冲body数据 避免未来的IO
      ResponseBody bufferedBody = Utils.buffer(rawBody);
      // 因为状态码不是正常的状态码 所以这里返回一个错误的Response
      return Response.error(bufferedBody, rawResponse);
    } finally {
      rawBody.close();
    }
  }

  if (code == 204 || code == 205) {
    // 204和205状态是没有body数据的
    rawBody.close();
    return Response.success(null, rawResponse);
  }
  
  // 构建一个包装异常的ResponseBody,将读取底层数据流时出现的异常进行捕获 并在下面抛出
  ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
  try {
    // 因为在这一步, 可能会出现responseConverter将异常捕获并不处理
    // 调用Convert组件进行转换
    T body = responseConverter.convert(catchingBody);
    return Response.success(body, rawResponse);
  } catch (RuntimeException e) {
    // 如果底层源抛出异常,则传播该异常,而不是指示它是运行时异常。
    catchingBody.throwIfCaught();
    throw e;
  }
}

首先第一步,就将原始的Response分为body和其他响应结果进行了分割,避免错误的使用导致body被重复读取。

随后在判断http code非200多的情况下,将原始body读取到缓存之后,构建了一个表示请求错误的Response返回。

否则,在正常的非204 205的情况下,就是使用convertbody数据读取转换成指定的对象了。在这一步,将原始的body进行包装,将读取流的所产生的异常给捕获了,避免Convert内部捕获但不抛出。

随后来到Convert,这里用一个简单的ToStringConverter来展示其核心概念

public static class ToStringConverterFactory extends Converter.Factory {
  static final MediaType MEDIA_TYPE = MediaType.get("text/plain");

  @Override
  public Converter<ResponseBody, String> responseBodyConverter(
    Type type, Annotation[] annotations, Retrofit retrofit) {
    if (String.class.equals(type)) {
      return ResponseBody::string;
    }
    return null;
  }

  @Override
  public Converter<String, RequestBody> requestBodyConverter(
    Type type,
    Annotation[] parameterAnnotations,
    Annotation[] methodAnnotations,
    Retrofit retrofit) {
    if (String.class.equals(type)) {
      return value -> RequestBody.create(MEDIA_TYPE, value);
    }
    return null;
  }
}

可以看到在调用完Convert之后,整个请求就真正结束了。

关于OkhttpCall的其他方法,都不是很难,同学们可以自行查看对应的源码。

2.5.2.2 ExecutorCallbackCall

Call的另外一个实现,通过类的名字定义可以大概得知,这是为了支持异步调用所实现的Call。实际上也确实如此,还记得最早的时候,在Platform那一章节,讲到过如果是Android平台的话,会默认添加一个MainThreadExecutor。而ExecutorCallbackCall就是为了适配MainThreadExecutor,达到Android平台下的回调效果(或者自定义Executor都行,在build Retrofit时可配置)

static final class ExecutorCallbackCall<T> implements Call<T> {
  final Executor callbackExecutor;
  final Call<T> delegate;

  ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
    this.callbackExecutor = callbackExecutor;
    this.delegate = delegate;
  }

  @Override
  public void enqueue(final Callback<T> callback) {
    // 调用代理对象的enqueue方法
    delegate.enqueue(
      // 生成一个Callback
      new Callback<T>() {
        @Override
        public void onResponse(Call<T> call, final Response<T> response) {
          // 内部调用executor的execute方法,异步执行
          callbackExecutor.execute(
            () -> {
              if (delegate.isCanceled()) {
                // 取消
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                // 正常
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            });
        }

        @Override
        public void onFailure(Call<T> call, final Throwable t) {
          // 失败 则使用executor的execute方法,将失败结果异步化
          callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
        }
      });
  }
posted @ 2021-09-14 15:44  卡卡一点都不卡  阅读(132)  评论(0编辑  收藏  举报