Retrofit源码流程分析

QuibblerQuibbler 2021-04-14 约 43 分钟 1636 次阅读

Retrofit源码流程分析

距离上次了解Retrofit的使用过去很长时间,必须得抽空看看Retrofit源码,了解Retrofit到底做了哪些工作,把网络请求封装的如此便捷。

按开发过程中Retrofit的使用顺序看源码。

1、Retrofit的构造

在开始Retrofit流程分析之前,先搞清楚Retrofit实例的构造,涉及到后面请求流程中一些关键对象的初始化。

1.1、构造者模式创建Retrofit实例

Retrofit和OkHttpClient一样采用建造者模式创建,Retrofit类内部提供Builder用来配置Retrofit。可以设置:Converter.Factory、CallAdapter.Factory、okhttp3.Call.Factory(也就是OkHttpClient)等属性,如果没有配置的话都会创建默认的实例。

val retrofit = Retrofit.Builder()
            .baseUrl(base_url)
            .addConverterFactory(GsonConverterFactory.create())
            .build()

必须提供Retrofit网络访问的baseUrl,在构造Retrofit实例的build()方法中我们看到会判断是否提供了baseUrl。

public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      ...
      return new Retrofit(
          callFactory,
          baseUrl,
          unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories),
          callbackExecutor,
          validateEagerly);
    }

1.2、平台抽象:Platform

Retrofit的回调是在主线程,OkHttp默认是在子线程。之所以Retrofit能完成切换,因为内部在回调时根据Android平台特性做了线程切换。

Retrofit在安卓平台Platform的子类是Android,其内部类MainThreadExecutor中通过获取主线程Looper构造Handler,以便任务切换回主线程。关于Handler是Android中必须深入理解的技术点,详见Handler消息机制原理。

static final class Android extends Platform {
    Android() {super(Build.VERSION.SDK_INT >= 24);}
    
    @Override
    public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
    ...
    
    //Android主线程Handler执行器
    static final class MainThreadExecutor implements Executor {
    
      private final Handler handler = new Handler(Looper.getMainLooper());
      
      @Override
      public void execute(Runnable r) {
        handler.post(r);
      }
      
    }
  }

在构造过程中如果没有给Retrofit建造者设置callbackExecutor,那么将会默认使用Platform提供的defaultCallbackExecutor()也就是前面刚刚提到的MainThreadExecutor,所以Retrofit的回调是在主线程中。

Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
      ...

之所以将平台相关的都抽象到Platform,是因为不仅在Android平台使用Retrofit,在IOS等其它平台都可以使用Retrofit,只需要实现对应的抽象平台即可。这也是Retrofit的可扩展性之一。

1.3、Converter和CallAdapter的创建

还记得在构造Retrofit实例的时候,调用Retrofit.Builder的addConverterFactory(Converter.Factory factory)和addCallAdapterFactory(CallAdapter.Factory factory)方法分别给Retrofit添加转换器和请求适配器。

/** Add converter factory for serialization and deserialization of objects. */
    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    }
    
    /**
     * Add a call adapter factory for supporting service method return types other than {@link
     * Call}.
     */
    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    }

如果开发者不设置,那么构造Retrofit时会借助Platform获取默认的OptionalConverterFactory和DefaultCallAdapterFactory添加给Retrofit实例。

因为服务端多数返回Json格式,所以通常设置的转换器是GsonConverterFactory;使用默认的DefaultCallAdapterFactory或者CompletableFutureCallAdapterFactory(在Java 8+ / Android API 24+使用后者,为了简化逻辑,这里我们统一使用DefaultCallAdapterFactory)。接口中方法的返回值类型是Call<T>。

public Retrofit build() {
      ...
      
      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
      
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories =
          new ArrayList<>(
              1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
      ...
      converterFactories.addAll(platform.defaultConverterFactories());
      
      return new Retrofit(...);
    }
  }

构造Retrofit时设置的转换器和适配器在后面网络请求的流程中会用到。

2、创建服务

构造好Retrofit实例之后,第二步就是通过create(Class<T> service)方法获取请求接口动态代理对象。从这个方法为入口,开启Retrofit网络请求的流程分析。


2.1、创建代理对象

通过Retrofit提供的丰富注解,开发者可以实现丰富的网络请求接口定义,详见Retrofit注解详细探究一文。定义好interface,就可以使用Retrofit的create(Class<T> service)方法创建动态代理对象:

public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
              private final Platform platform = Platform.get();
              private final Object[] emptyArgs = new Object[0];
              @Override
              public @Nullable 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);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

涉及到Java基础:动态代理机制,这里不展开讨论,推荐阅读《Thinking in Java》。

2.2、解析接口方法注解

通过create(final Class<T> service)方法获取代理对象,再通过代理对象调用请求方法。当调用动态代理对象的方法时,会将其方法调用转发至代理的InvocationHandler,通过invoke()完成最终的调用。

@Override
    public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
        throws Throwable {
      ...
      return platform.isDefaultMethod(method)
          ? platform.invokeDefaultMethod(method, service, proxy, args)
          : loadServiceMethod(method).invoke(args);
    }

Platform平台在1.2节提到过,在安卓平台的实现是Android,安卓框架中Executable的isDefaultMethodInternal()方法返回值是false,所以执行后面的loadServiceMethod(method)。

通过loadServiceMethod(method)解析出使用注解定义的接口方法:

ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

这里用到了serviceMethodCache缓存以提高运行效率,如果已解析过对应方法,那么直接复用缓存中的。并且会将解析过的方法也放入缓存中。

private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();

如果缓存中没有找到方法缓存,那么就得通过ServiceMethod方法解析注解获取对应的ServiceMethod。

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    //第一步
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    ...
    //第二步返回
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

这里分为两步,第一步先创建请求工厂RequestFactory,根据注解的method创建请求实例。

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

同样是建造者模式创建RequestFactory,传入Retrofit实例和定义的注解方法method。

Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

最后再build()出一个请求工厂RequestFactory。在Retrofit注解详细探究一文中了解到所有注解的解析工作和异常抛出都在这一步涉及到的几个方法中:

RequestFactory build() {
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      ...
      //很多校验,不符合就抛出异常
      return new RequestFactory(this);
    }
    //解析网络请求注解
    private void parseMethodAnnotation(Annotation annotation)
    //解析网络请求方法和路径
    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) 
    //解析网络请求头
    private Headers parseHeaders(String[] headers)

第二步则是通过HttpServiceMethod的parseAnnotations(Retrofit, Method, RequestFactory)方法创建HttpServiceMethod。

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    ...
    
    //从Retrofit获取CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
        
    //对Response类型进行各种判断
    Type responseType = callAdapter.responseType();
    if (responseType == okhttp3.Response.class) {
      throw methodError(
          method,
          "'"
              + getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }
    
    //比如HEAD不能有返回类型必须为Void
    //TODO support Unit for Kotlin?
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }
    
    //创建响应转换器ResponseConverter
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
    //这里的Factory就是OkHttpClient
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    
    //最后更具三种不同的情况创建HttpServiceMethod抽象类的实现类
    //有三种,分别是:CallAdapted、SuspendForResponse、SuspendForBody
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(...);
    } else if (continuationWantsResponse) {
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(...);
    } else {
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForBody<>(...);
    }
  }

2.3、invoke代理方法

经过2.2节 loadServiceMethod(method)解析注解方法,拿到ServiceMethod实例。


接下来将调用它的invoke(Object[] args)方法,在ServiceMethod中还是抽象方法:

abstract @Nullable T invoke(Object[] args);

HttpServiceMethod继承自ServiceMethod类实现了invoke(Object[] args)方法:

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

先将请求封装成OkHttpCall,再继续调用HttpServiceMethod的抽象方法adapt(Call<ResponseT> call, Object[] args):

protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

在前面2.2节提到过,HttpServiceMethod内部有三个实现子类,分别是CallAdapted、SuspendForResponse、SuspendForBody。

在创建HttpServiceMethod实例的时候会根据isKotlinSuspendFunction和continuationWantsResponse这两个条件判断是否支持Kotlin协程 (涉及到Kotlin协程,Kotlin将回调函数转换成协程,这里暂不展开讨论),再从上面三个HttpServiceMethod子类中选择一个合适的类型创建实例。

以创建的CallAdapted类型实例为例:

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;
    
    CallAdapted(
        RequestFactory requestFactory,
        okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }
    
    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
  }

CallAdapted中的callAdapter成员是在CallAdapted构造的时候初始化,参数在HttpServiceMethod类的parseAnnotations(Retrofit, Method, RequestFactory)方法中由createCallAdapter(...)创建:

CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);

createCallAdapter(...)方法实现如下,内部借助Retrofit对象获取CallAdapter实例。

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

从Retrofit中的callAdapterFactories中获取CallAdapter实例的callAdapter()方法实现如下:

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

  public CallAdapter<?, ?> nextCallAdapter(
      CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
    ...
    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;
      }
    }
    ...
  }

callAdapterFactories在Retrofit构造的时候初始化,在1.3节提到过。开发者没有设置那么会使用默认的DefaultCallAdapterFactory。其实还有另一个内置的CompletableFutureCallAdapterFactory,这里不再详细展开讨论。而且从API 24及以后都是使用后者作为Retrofit默认的CallAdapter。

public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    ...
    
    //返回封装了OkHttp Call的ExecutorCallbackCall
    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }
      @Override
      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

最终到这里通过默认的DefaultCallAdapterFactory get到我们熟悉的Call<T>实例,也就是定义网络请求接口方法的返回类型。

3、网络请求

通过Retrofit拿到封装了OkHttp请求的Call<T>实例,接下来就是完成网络请求。和OkHttp一样,Retrofit提供两种请求方式:异步enqueue()和同步execute()。

3.1、异步网络请求

ExecutorCallbackCall定义在DefaultCallAdapterFactory工厂类中,实现了Call<T>接口。调用enqueue(Callback<T> callback)方法完成异步网络请求。


其中ExecutorCallbackCall的enqueue(Callback<T> callback)方法实现如下:

@Override
    public void enqueue(final Callback<T> callback) {
      
      delegate.enqueue(
          new Callback<T>() {
          
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              //回调通过callbackExecutor在主线程调用
              callbackExecutor.execute(
                  () -> {
                    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<T> call, final Throwable t) {
              //回调通过callbackExecutor在主线程调用
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }

内部通过delegate的enqueue(Callback<T> callback)方法实现异步,那么这个delegate又是什么?

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;
    }
    ...
  }

从DefaultCallAdapterFactory工厂创建CallAdapter匿名内部类的方法中可以看到,传入的delegate就是adapt(Call<Object> call)方法传入的call参数:

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

而这个call在2.3节中我们已经知道其实就是OkHttpCall,在调用HttpServiceMethod的invoke(Object[] args)方法中创建:

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

捋清delegate是什么之后,继续看异步调用逻辑:

public void enqueue(final Callback<T> callback) {
    okhttp3.Call call;
    ...
    //从Retrofit的Call,创建okhttp3.Call
    call = rawCall = createRawCall();
    ...
    
    //使用OkHttp请求网络。
    call.enqueue(
        new okhttp3.Callback() {
          @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
            Response<T> response;
            ...
            //在这里通过Converter将OkHttp的响应转换成熟肉数据
            response = parseResponse(rawResponse);
            ...
            callback.onResponse(OkHttpCall.this, response);
          }
          
          @Override
          public void onFailure(okhttp3.Call call, IOException e) {
            //失败回调
          }
        });
  }

OkHttpCall中的enqueue()逻辑就很明确,创建OkHttp的Call网络请求,通过OkHttp实现最终的网络请求。并且在响应回调中使用parseResponse(okhttp3.Response rawResponse)方法,通过responseConverter将原始Response响应转换成需要的结果。

关于OkHttp异步网络请求就不再赘述,详见OkHttp网络请求流程。

3.2、同步网络请求

Retrofit的同步网络请求就更直接了:经过ExecutorCallbackCall的execute()方法,再调用OkHttpCall中的execute()方法,最终调用OkHttp库中Call请求的execute()方法完成同步网络请求。


关于OkHttp同步请求,也详见OkHttp网络请求流程。

相关推荐

精选
Airbnb开源项目
开源

Airbnb开源项目

Airbnb Engineering & Data ScienceAirflow Use Apache Airflow (incubating) to author workflows as directed acyclic graphs (DAGs) of tasks12,263Airpal Web UI for PrestoDB2,502Aerosolve A machine learning

1.8k
OkHttp线程池和连接池
开源

OkHttp线程池和连接池

OkHttp线程池和连接池了解了OkHttp的网络请求流程以及拦截器实现原理,再关注OkHttp中两个重要的:OkHttp的线程池和连接池。1、OkHttp线程池在OkHttp网络请求流程一文中,我们分析了OkHttp异步和同步请求流程。请求最后都在Dispatcher中分发调度处理,最后被ExecutorService执行。1.1、DispatcherDispatcher中执行任务的执行器是ex

5.2k
优美的开源动效库:Lottie
开源

优美的开源动效库:Lottie

优美的开源动效库:Lottie1、强大的动效LottieLottie是一个适用于Android,iOS,Web和Windows的库,它可以使用Bodymovin解析以json格式导出的Adobe After Effects动画,并在移动设备和Web上原生渲染它们!GitHub:https://github.com/airbnb/lottie-androidLottie官网:http://airbn

4.3k