Retrofit第一章-原理

856 阅读7分钟

Retrofit无疑是一个成功的网络框架,它本身并不执行网络请求,而是给我们留下了很多网络封装的想象空间,这也是它的成功之处。

接下来,我们通过一个简单的网络请求,来看看它的内部是怎么设计的。

基于retrofit:2.9.0

Retrofit的使用

在这一节,我们写一个网络请求示例,以用来进行源码分析。如下所示

//首先定义一个WanAndroidService
interface WanAndroidService {
    @GET("banner/json")
    fun banner(): Call<Banner>
}

//进行Retrofit初始化
val retrofit = Retrofit.Builder()
    .baseUrl("https://www.wanandroid.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

//进行请求
val service: WanAndroidService = retrofit.create(WanAndroidService::class.java)
service.banner().enqueue(object : Callback<Banner> {
    override fun onResponse(call: Call<Banner>, response: Response<Banner>) {
    }
    override fun onFailure(call: Call<Banner>, t: Throwable) {
    }
})

在此先感谢鸿神提供开放API,这里展示的是请求wanAndroid网站的banner,并且添加了GsonConverterFactory解析功能。

Retrofit原理

步骤1:Retrofit#create()

为什么不从Retrofit.Builder()初始化开始呢?因为Retrofit.Builder是一些配置条件,最终会呈现在Retrofit实例中。

这里贴一下Retrofit#create()的部分源码

public <T> T create(final Class<T> service) {
  return (T)
  	//代码1
      Proxy.newProxyInstance(
          service.getClassLoader(),
          new Class<?>[] {service},
          new InvocationHandler() {
            private final Platform platform = Platform.get();
            @Override
            public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                throws Throwable {
              args = args != null ? args : emptyArgs;
              //代码2
              return platform.isDefaultMethod(method)
                  ? platform.invokeDefaultMethod(method, service, proxy, args)
                  : loadServiceMethod(method).invoke(args);
            }
          });
}

其中省略了一些校验逻辑,并不影响我们走流程。

首先来看看代码1,我们遇到了Proxy.newProxyInstance(),这便是Retrofit的设计理念之一,动态代理,想必很多人都已经听过了。动态代理平时开发中不怎么用到,这里提一嘴它的用处。

我们有一个interface A,那如果我要实现它,方法之一就是

class B implements A

那我觉得这样太麻烦了,可不可以不编写class B,在运行时创建interface A的示例呢,动态代理就出场了,这里动态和静态是相对的,class B可理解为静态

编写动态代理的方式就是Proxy.newProxyInstance(),传入需要代理的classLoader,interface,以及InvocationHandler,这里的InvocationHandler可理解为接口A的动态实例。

InvocationHandler的invoke()方法可以理解为对接口中方法的解析

关于动态代理的使用其实并不复杂,我们主要能理解InvocationHandler#invoke()即可。Retrofit#create()的方法,到这里就结束了,它就是返回了一个动态代理对象。

那当我们进入到InvocationHandler#invoke()方法的时候,其实代码已经走到了

val service: WanAndroidService = retrofit.create(WanAndroidService::class.java)
service.banner()

只不过,我们还没有调用enqueue()方法

我们调用service.banner()时,就已经来到了代码2

platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args)

这里是一个条件判断,platform.isDefaultMethod(),用来判断是否是默认的接口实现,这是Java8的特性,很显然我们定义的WanAndroidService#banner()并没有默认实现。

那么就会调用loadServiceMethod()方法,接着来看

步骤2:Retrofit#loadServiceMethod()

ServiceMethod<?> loadServiceMethod(Method method) {
  ...缓存逻辑
  result = ServiceMethod.parseAnnotations(this, method);
  ...缓存逻辑
  return result;
}

在删除缓存逻辑之后,可以看到执行ServiceMethod#parseAnnotations()方法,得到了一个result。我们继续跟进

步骤3:ServiceMethod#parseAnnotations()

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
  //代码1
  RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
  ...校验逻辑
  //代码2
  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

在删除部分校验逻辑逻辑之后,值得一看的有两个方法,先来看代码1。

步骤4:RequestFactory#parseAnnotations()

static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
  return new Builder(retrofit, method).build();
}

这里直接调用了Builder,然后直接构造出了一个RequestFactory实例,那我们来看看在build()方法里做了什么。

步骤5:RequestFactory#build()

RequestFactory build() {
  for (Annotation annotation : methodAnnotations) {
    //代码1
    parseMethodAnnotation(annotation);
  }
  ....
  int parameterCount = parameterAnnotationsArray.length;
  parameterHandlers = new ParameterHandler<?>[parameterCount];
  for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
    parameterHandlers[p] =
    //代码2
        parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
  }
  ...
  return new RequestFactory(this);
}

这个方法,我们大致看一下就好,主要是一些判断条件,比如代码1,parseMethodAnnotation(),主要是对我们定义的方法的注解进行解析,比如说我们定义的@GET注解,标记它是个GET方法,这里简单贴了一下代码

private void parseMethodAnnotation(Annotation annotation) {
  if (annotation instanceof DELETE) {
    parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
  } else if (annotation instanceof GET) {
    parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
  } else if (annotation instanceof HEAD) {
  	...
  }
  ...
}

包括代码2,parseParameter()进行参数的解析,也包括参数的注解,比如我们例子中没有的@Query注解。

build()方法在这些解析方法之后就结束了,并将这些信息全部封装到一个RequestFactory实例中。到这里,我们就结束了步骤3中代码1的逻辑。让我们来到步骤3的代码2

步骤6:步骤3的代码2-HttpServiceMethod#parseAnnotations()

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
  ...
  //代码1
  adapterType = method.getGenericReturnType();
  ...
  //代码2
  CallAdapter<ResponseT, ReturnT> callAdapter =
      createCallAdapter(retrofit, method, adapterType, annotations);
  Type responseType = callAdapter.responseType();
  ...
  //代码3
  Converter<ResponseBody, ResponseT> responseConverter =
      createResponseConverter(retrofit, method, responseType);
  ...
  //代码4
  return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  ...
}

这是很关键的一个步骤,在精简了代码之后,可以看到它的逻辑。代码分为4步,我也将各个步骤的逻辑罗列出来了

  1. 获取方法的返回值
  2. 根据返回值匹配CallAdapter
  3. 将返回值类型传给Converter,从而构建出合适的Converter实例
  4. 返回CallAdapted实例

接下来,我们一步一步分析。

步骤7:步骤6的代码1 - method.getGenericReturnType()

我们来分析一下步骤6的代码1

这里调用的是与Java反射相关的方法,获取对应方法的返回值类型,我们示例代码中就一个方法,这里贴一下

interface WanAndroidService {
    @GET("banner/json")
    fun banner(): Call<Banner>
}

可以知晓method指的是banner()方法,那method.getGenericReturnType()这个返回值就是Call,而不是Banner

步骤8:步骤6的代码2 - HttpServiceMethod#createCallAdapter()

紧接着来分析步骤6的代码2

private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
    Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
    ...
  return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
}

可以看到,在内部调用了retrofit.callAdapter()方法,让我们再回到Retrofit类

步骤9:Retrofit#callAdapter()

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
  return nextCallAdapter(null, returnType, annotations);
}

public CallAdapter<?, ?> nextCallAdapter(
    @Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
  //由于skipPast是null,那么start = 0
  int start = callAdapterFactories.indexOf(skipPast) + 1;
  for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
    CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
      //匹配到了
      return adapter;
    }
  }
  ...异常信息
}

这也是比较重要的代码,在callAdapter()方法内部调用了nextCallAdapter()方法,可以看到,nextCallAdapter()第一参数为null的目的是遍历所有的CallAdapterFactory,如果匹配到了,就返回对应的CallAdapter。这里最终匹配的是DefaultCallAdapterFactory,因为我们没有自定义CallAdapterFactory,所以这里返回的是默认的CallAdapterFactory,调用DefaultCallAdapterFactory的get()方法后获取到了它的一个匿名对象DefaultCallAdapterFactory$CallAdapter()

关于callAdapterFactories初始化,以及Retrofit默认的CallAdapterFactory文末会有交代,这里先走流程。

到这里,步骤8,也就是步骤6的代码2也分析完了,接着来看步骤6的代码3

步骤10:步骤6的代码3 - HttpServiceMethod#createResponseConverter()

private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
    Retrofit retrofit, Method method, Type responseType) {
  Annotation[] annotations = method.getAnnotations();
  ...
  return retrofit.responseBodyConverter(responseType, annotations);
}

这块代码和步骤8很相似,不过步骤8是获取CallAdapter,这里是获取Converter。一个是请求,一个是结果转换,实际上他们的代码逻辑是一样的。我们再次来到Retrofit类

步骤11:Retrofit#responseBodyConverter()

public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
  return nextResponseBodyConverter(null, type, annotations);
}

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
    @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
  int start = converterFactories.indexOf(skipPast) + 1;
  for (int i = start, count = converterFactories.size(); i < count; i++) {
    Converter<ResponseBody, ?> converter =
        converterFactories.get(i).responseBodyConverter(type, annotations, this);
    if (converter != null) {
      return (Converter<ResponseBody, T>) converter;
    }
  }
}

这里就不解释了,和查找CallAdapter的逻辑是一样的。

不过不一样的是,我们添加了一个自定义的GsonConverterFactory,所以调用的是GsonConverterFactory#responseBodyConverter()方法,返回的是GsonResponseBodyConverter(),那如果我不自定义呢?默认是什么,同样在文末交代。我们接着走流程,那么到这里步骤6代码3就已经结束了。

步骤12:步骤6的代码4 - new CallAdapted()

在这一步骤,我们来给已经获取到的这些关键信息搞个封装。

//步骤6代码4
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);

可以看到调用CallAdapted构造方法,这里CallAdapted是什么呢?其实是HttpServiceMethod$CallAdapted。

它的构造中传入的各个参数,我们一一列出来

  1. requestFactory是请求信息的封装,来源于步骤5
  2. callFactory是OkHttpClient对象,上文没有交代,我会在文末交代
  3. responseConverter是步骤11的GsonResponseBodyConverter()
  4. callAdapter是DefaultCallAdapterFactory$CallAdapter(),步骤9可知

到此,步骤6完结。然后步骤3结束,步骤2结束,我们最终返回CallAdapted实例。

注意:这里以“call”开头的类和对象比较多,其实不一样,要区分来源

步骤13:步骤1的loadServiceMethod().invoke()

到步骤12,还没有结束,我们在步骤1中分析完loadServiceMethod()返回CallAdapted实例,还需要调用invoke()方法。那我们就来看看具体方法

步骤14:CallAdapted#invoke()

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

其实这个invoke()方法并不属于CallAdapted(),而是属于他的父类HttpServiceMethod,CallAdapted既是HttpServiceMethod内部类,又是HttpServiceMethod的子类,CallAdapted结构如下。

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT>

我们接着来看invoke()方法。就两行代码,很简单。

  1. OkHttpCall初始化
  2. 调用adapt()方法,传入OkHttpCall实例

那,我们来看看adapt()方法

步骤15:CallAdapted#adapt()

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

在CallAdapted的父类HttpServiceMethod中,adapt()是一个抽象方法,交给子类CallAdapted实现。这里可以看到,继续调用了callAdapter的adapt()方法,OkHttpCall()对象继续作为参数传入,由步骤12可知callAdapter是DefaultCallAdapterFactory$CallAdapter对象,那我们接着来看

步骤16:DefaultCallAdapterFactory$CallAdapter#adapt()

//代码1
final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

      @Override
      public Call<Object> adapt(Call<Object> call) {
      	//代码2
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };

步骤9提到过的匿名对象在这里展现出来。看代码2,它的adapt()方法表明返回值与executor有关。那executor是不是空呢?

我们来看代码1,其中

Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)

这行代码的意思是annotations中有没有包含SkipCallbackExecutor对象,很显然,我们没有使用带有SkipCallbackExecutor的注解。所以这里是false,继而代码2处返回值为new ExecutorCallbackCall()。

到这里步骤14和13也结束了,我们得到了ExecutorCallbackCall()对象。接下来再回看步骤1

return loadServiceMethod(method).invoke(args)

这行代码的返回值是ExecutorCallbackCall()对象,这个返回值是动态代理的结果,也就是

val service: WanAndroidService = retrofit.create(WanAndroidService::class.java)
service.banner()

service.banner()的返回值。

接下来应该进入enqueue(...)流程了。

步骤17:ExecutorCallbackCall#enqueue()

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) {
    //代码1
    delegate.enqueue(
        new Callback<T>() {
          @Override
          public void onResponse(Call<T> call, final Response<T> response) {
            //代码2
            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) {
            callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
          }
        });
  }
  ....
}  

ExecutorCallbackCall是Call对象的子类,从代码1中可以看到,并不是ExecutorCallbackCall本身执行enqueue()方法,而是通过delegate执行enqueue(),这个delegate从构造方法中来,那么我们从步骤14,步骤15,步骤16可以得知,这个delegate是OkHttpCall。

那我们再来到OkHttpCall的enqueue()看看

步骤18:OkHttpCall#enqueue()

@Override
public void enqueue(final Callback<T> callback) {
  ...
  okhttp3.Call call;
  ...
  call = rawCall = createRawCall();
  ...
  //代码1
  call.enqueue(
      new okhttp3.Callback() {
        @Override
        public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
          Response<T> response;
          ...
          //代码2
          response = parseResponse(rawResponse);
          ...
          //代码3
          callback.onResponse(OkHttpCall.this, response);
        }
        @Override
        public void onFailure(okhttp3.Call call, IOException e) {
          callFailure(e);
        }
        private void callFailure(Throwable e) {
            callback.onFailure(OkHttpCall.this, e);
        }
      });
}

到这里总算是守得云开见月明了,代码1中call.enqueue()这里的call已经是okhttp3.Call的Call对象了,调用enqueue()表示网络请求放在子线程执行,okhttp的onResponse回调也是在子线程。接着代码2,解析rawResponse,也就是原始的Response,代码2稍候再细看,接着代码3回调,也是子线程。

再回到步骤17,Callback在子线程怎么办?Retrofit可是在主线程回调的,不急,继续往下看

步骤19:步骤17代码2-callbackExecutor.execute()

步骤17中的代码2有一个callbackExecutor,这是什么呢?我们看到这个callbackExecutor是在ExecutorCallbackCall构造方法中传入的,其实这是Retrofit在Android平台提供的MainThreadExecutor,这里先按下不表,同样看文末。

那我们就来看看这个MainThreadExecutor

static final class MainThreadExecutor implements Executor {
  private final Handler handler = new Handler(Looper.getMainLooper());
  @Override
  public void execute(Runnable r) {
    handler.post(r);
  }
}

很简单,execute()方法就是切主线程,所以步骤17代码2,成功切换到了主线程。

到这里逻辑已经梳理完毕了。

我们再回过头看看,留下了哪些问题。

问题1:步骤18代码2的parseResponse()还没解决呢

我们来看看怎么解析的

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
  ResponseBody rawBody = rawResponse.body();
  int code = rawResponse.code();
  //代码1
  if (code < 200 || code >= 300) {
  }
  if (code == 204 || code == 205) {
  }
  ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
  //代码2
  T body = responseConverter.convert(catchingBody);
  return Response.success(body, rawResponse);
}

代码1判断code,代码2执行解析,我们直接来看解析。

responseConverter是谁还记得吗?步骤12里讲过是GsonResponseBodyConverter,那直接来看代码

@Override
public T convert(ResponseBody value) throws IOException {
  JsonReader jsonReader = gson.newJsonReader(value.charStream());
  T result = adapter.read(jsonReader);
  return result;
}

很简单,就是Gson解析。

问题2:Retrofit默认的CallAdapterFactory怎么来的,默认的Converter是什么,callFactory为什么是OkHttpClient对象,MainThreadExecutor在哪里初始化

这些问题之所以放在一起,是因为他们初始化的时机都差不多。

来看下Retrofit#build()方法

public Retrofit build() {
  
  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
  	//默认的callFactory是OkHttpClient(),因为我们没有自定义OkHttpClient
    callFactory = new OkHttpClient();
  }
  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {
  	//代码1
    callbackExecutor = platform.defaultCallbackExecutor();
  }
  //我们自定义的callAdapterFactories,这里是空
  List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  //代码2   默认的callAdapterFactories
  callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
  
  List<Converter.Factory> converterFactories =
      new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
  
  converterFactories.add(new BuiltInConverters());
  converterFactories.addAll(this.converterFactories);
  //代码3   默认的ConverterFactories
  converterFactories.addAll(platform.defaultConverterFactories());
  return new Retrofit(
      callFactory,
      baseUrl,
      unmodifiableList(converterFactories),
      unmodifiableList(callAdapterFactories),
      callbackExecutor,
      validateEagerly);
}

代码1,2,3都与platform有关,这个Platform是平台,接下来再来看看Platform类

class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  //这里指定了Android平台
  private static Platform findPlatform() {
    return "Dalvik".equals(System.getProperty("java.vm.name"))
        ? new Android()
        : new Platform(true);
  }

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

  //Android平台代码
  static final class Android extends Platform {
    Android() {
      super(Build.VERSION.SDK_INT >= 24);
    }

    @Override
    public Executor defaultCallbackExecutor() {
      //线程调度
      return new MainThreadExecutor();
    }

    static final class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override
      public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
}

现在只剩下一个问题,默认的Converter是什么?

虽然在Retrofit#build()中有指定defaultConverterFactories以及默认的BuiltInConverters,但其实我们去掉GsonConverterFactory后会报错在步骤10。原理跟匹配CallAdapterFactory一样,没有匹配到对应的Converter。

Could not locate ResponseBody converter for class com.example.test.Banner

在文章中我省略了很多代码,有兴趣的同学可以自行查看。

继续看第二章-kotlin协程的支持