【Retrofit2进阶】---从源码角度看Retrofit2实现原理

前言

本文是Retrofit2进阶系列的第一篇---从源码角度看Retrofit2实现原理,我会尽可能用简洁的代码帮大家理解Retrofit实现一次网络请求的核心流程是怎样的,这个流程整体上就4个步骤,是不复杂的,希望大家带着信心读下去,在文章末尾,我也为大家做出了简单的总结,希望能帮大家更好的理解这个框架,希望在读文章的你能有一些收获,能有更大的进步。

先来看一个最基础的网络请求案例:

//1、创建Retrofit接口
public interface ApiService {
    @GET("/")
    Observable getData();
    @GET("/")
    Call getData2();
}

//2、retrofit相关配置 
Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://xxxx/")
                    .client(client)
                    //json转换
                    .addConverterFactory(GsonConverterFactory.create())
                    //RxJava2转换器
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
//创建接口对象
ApiService apiService = retrofit.create(ApiService.class);

//3、接口方法调用
3.1 call调用
apiService.getData2().enqueue();

3.2结合rxjava调用
apiService.getData().subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe();

下面就来分析一下Retrofit2是如何完成一次完整的网络请求的。

先来看一下Call调用

public interface ApiService {
    @GET("/")
    Call getData2();
}

通过接口调用会返回一个Call对象,如果你看过OkHttp源码的话,应该会对这个Call很熟悉,它封装了一个网络请求的任务,但是它却不做网络请求,而是通过调用enqueue()或者execute()来发起真正的网络请求。

那这个Call对象如何生成的?其实可以在retrofit.create()方法中找到答案。

public  T create(final Class service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod serviceMethod =
                (ServiceMethod) loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }
 
 

create()内部的核心就一件事情,通过动态代理生成一个代理类对象,具体来说就是通过Proxy.newProxyInstance()来创建的。然后在回调方法invoke()内部通过一系列解析,包装,最终返回用于发起网络请求的Call对象或者用于结合rxjava使用的Observable对象。

这里的关键点与难点在于,你要懂代理模式和动态代理,如果你还不会的话,建议先简单学习一下再接着往下看,不然很多逻辑的连贯性你是不懂的。这里推荐一下我之前的一篇文章Java动态代理那些你容易忽略的细节。

先说一下Retrofit2动态代理的逻辑

//retrofit的API接口对象
ApiService apiService;
//创建代理对象
 apiService = retrofit.create(ApiService.class);
//调用代理类中的方法
apiService.xxx();

首先生成一个代理类对象,当调用代理类的方法时,会回调执行InvocationHandlerinvoke()方法

@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            //省略,不会执行的代码

            //生成Call关键在这里
            ServiceMethod serviceMethod =
                (ServiceMethod) loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
 
 
  • ServiceMethod是对接口中的方法进行解析,包括注解、参数,生成Http Request,具体来说是toRequest(),将response转换为String或者实体类,具体说是toResponse()
  • OkHttpCall是对okhttp3.call的封装,以及okhttp3的其他方法的调用;
  • serviceMethod.callAdapter.adapt(okHttpCall);通过calladapter转换器,将 okhttp3.call转换成可以用于发起网络请求的retrofit2.Call或者说用于rxjava的Observable

下面对ServiceMethodOkHttpCallCallAdapter做一个简单的解释,注意不是详解,这样可以让你避免陷入一叶障目的困境。我们先搞清楚主流程,那些细枝末节后面再看呗。

1、ServiceMethod
它是通过建造者模式来创建的,核心内容如下:
这部分内容先不用详细理解,可以先看个大概,后面再单独来看

 public ServiceMethod build() {
        //获取具体的网络适配器对象CallAdapter,如果retrofit配置了rxjava2转换器,那这里就是RxJava2CallAdapter
       callAdapter = createCallAdapter();
        
       responseType = callAdapter.responseType();
      //获取响应转换器
     responseConverter = createResponseConverter();

      //解析方法注解,比如@GET、@POST、@FormUrlEncoded等等
      //这里解析完毕之后可以获取到Http请求方式,请求体,url等信息
      for (Annotation annotation : methodAnnotations) {
            parseMethodAnnotation(annotation);
      }

      //解析当前方法的参数
int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        if (Utils.hasUnresolvableType(parameterType)) {
          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

}

2、OkHttpCall
它继承于Retrofit2.Call,内部就是对okhttp3一系列操作的封装,甚至说代码都是直接copy的。这里就不展开详细解释了。注意:不要被OkHttpCall的名字所迷惑,它不是okhttp3中的call,而是Retrofit2.Call

final class OkHttpCall implements Call {
  private final ServiceMethod serviceMethod;
  private final @Nullable Object[] args;

  private volatile boolean canceled;

  @GuardedBy("this")
  private @Nullable okhttp3.Call rawCall;
  @GuardedBy("this")
  private @Nullable Throwable creationFailure; // Either a RuntimeException or IOException.
  @GuardedBy("this")
  private boolean executed;

  OkHttpCall(ServiceMethod serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }

3、callAdapter
上面invoke()方法中,最后一步是return serviceMethod.callAdapter.adapt(okHttpCall);
上面有提到过,这一步的作用是返回一个Retrofit2.Call或者Observable

这里的CallAdapter对象是一个接口对象,所以需要找到他的实现类。先回顾一下在Retrofit配置的时候,有这么一行代码.addCallAdapterFactory(RxJava2CallAdapterFactory.create()),它可以将接口方法返回Observable,如果不加这个配置,会如何呢?答案是会返回Retrofit2.Call类型,具体是如何产生的,请看如下流程:

retrofit.build()---->platform.defaultCallAdapterFactory()--->Platform.ExecutorCallAdapterFactory--->ExecutorCallAdapterFactory.ExecutorCallbackCall

3.1 Retrofit没有配置callAdapter时
serviceMethod.callAdapter就是ExecutorCallAdapterFactory.get()返回的CallAdapter实例,然后调用它的adapt会返回一个ExecutorCallbackCall对象。简单看一下这个对象,它是继承于Call的。

static final class ExecutorCallbackCall implements Call {

3.2 Retrofit配置了RxJava2CallAdapterFactory时
serviceMethod.callAdapter就是RxJava2CallAdapter,调用它的adapt会返回一个Observable对象。

到这里就搞清楚了生成Retrofit2.Call或者Observable的整个流程,最后就只剩下一步了,发起网络请求和响应是如何实现的。

4、网络请求的实现
4.1 Call实现网络请求
上面提到过Call对象是通过enqueue()或者execute()发起网络请求的,而这个Call对象实际上是ExecutorCallbackCall的实例

static final class ExecutorCallbackCall implements Call {
    final Executor callbackExecutor;
    final Call delegate;

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

    @Override public void enqueue(final Callback callback) {
      checkNotNull(callback, "callback == null");

      delegate.enqueue(new Callback() {
        @Override public void onResponse(Call call, final Response response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

        @Override public void onFailure(Call call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

所以,当我们外部调用enqueue()时,实际调用的就是ExecutorCallbackCall.enqueue(),而这里的delegateOkHttpCall,所以最终会由OkHttpCall内部的okhttp3去执行。

这里还有一个关键点callbackExecutor,它的来源如下:

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

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

可以看到enqueue的回调结果是在主线程中。

4.2 Observable实现网络请求
从之前的分析中,我们可以知道Observable是在RxJava2CallAdapter内部的adapt()方法返回的:

@Override public Object adapt(Call call) {
    //创建一个发射网络返回数据的Observable
    Observable> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

    //这里为null
    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    //可以转换成Flowable
    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }

关键点在第一行代码,isAsync返回true,所以看一下CallEnqueueObservable的实现


final class CallEnqueueObservable extends Observable> {
  private final Call originalCall;

  CallEnqueueObservable(Call originalCall) {
    this.originalCall = originalCall;
  }

  @Override protected void subscribeActual(Observer> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    Call call = originalCall.clone();
    CallCallback callback = new CallCallback<>(call, observer);
    observer.onSubscribe(callback);
    call.enqueue(callback);
  }

如果你看过RxJava2的源码的话,应该对这段代码非常熟悉,每个Observable都会去调用subscribeActual()方法。这里通过call.enqueue()去发起网络请求,然后通过CallCallback回调

private static final class CallCallback implements Disposable, Callback {
    private final Call call;
    private final Observer> observer;
    boolean terminated = false;

    CallCallback(Call call, Observer> observer) {
      this.call = call;
      this.observer = observer;
    }

    @Override public void onResponse(Call call, Response response) {
      if (call.isCanceled()) return;

      try {
        observer.onNext(response);

        if (!call.isCanceled()) {
          terminated = true;
          observer.onComplete();
        }
      } catch (Throwable t) {
        if (terminated) {
          RxJavaPlugins.onError(t);
        } else if (!call.isCanceled()) {
          try {
            observer.onError(t);
          } catch (Throwable inner) {
            Exceptions.throwIfFatal(inner);
            RxJavaPlugins.onError(new CompositeException(t, inner));
          }
        }
      }
    }

    @Override public void onFailure(Call call, Throwable t) {
      if (call.isCanceled()) return;

      try {
        observer.onError(t);
      } catch (Throwable inner) {
        Exceptions.throwIfFatal(inner);
        RxJavaPlugins.onError(new CompositeException(t, inner));
      }
    }

    @Override public void dispose() {
      call.cancel();
    }

    @Override public boolean isDisposed() {
      return call.isCanceled();
    }
  }
}

这里的逻辑也很简单,就是把网络请求的结果发射出去。

到这里,Retrofit2网络执行流程的源码分析就算完了。其实这里的类不算多,逻辑上也比较清晰,但是需要掌握的知识点比较杂,比如入口处的动态代理,中间的OkHttpRxJava2源码。所以,这里建议基础薄弱的同学,看完这些内容之后再回头来看Retrofit2,理解会更加深刻。


总结

流程
1、通过建造者模式创建一个Retrofit实例,也就是做Retrofit相关配置;
2、通过Retrofit对象的creat()方法创建一个代理对象,当调用接口方法时,都会调用动态代理的invoke()方法;
3、invoke()内部做了3件事情:

  • 3.1 会对method进行解析,最后生成ServiceMethod对象,并缓存起来,下次调用就不需要解析了;
  • 3.2 将原始的okhttp3.call封装成OkHttpCall
  • 3.3 通过CallAdapter转换成Call对象或者Observable对象

4、如果返回Call对象,调用execute或者enqueue方法去做网络请求;如果返回Observable对象,则结合rxjava2做后续的操作。

结论:

  • Retrofit是一个封装了网络请求的框架,它本身是不做网络请求的,而是通过Okhttp实现的;

  • Retrofit提供了一种更简洁的发起网络请求的方式,具体来说是通过接口和注解的方式来简化网络请求相关的一系列配置;

  • 可扩展性。比如说Client、数据转换Gson、RxJava适配等。

你可能感兴趣的:(【Retrofit2进阶】---从源码角度看Retrofit2实现原理)