Retrofit2源码解析

前言

上一篇文章中讲解了Retrofit的基本使用,分为如下几个步骤:

  • Step1 定义接口层
public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}
  • Step2 通过Retrofit创建接口层的一个代理对象
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

GitHubService service = retrofit.create(GitHubService.class);
  • Step3 从代理对象中生成一个Call
Call<List<Repo>> repos = service.listRepos("octocat");
  • Step4 通过Call来执行同步/异步请求
// 同步请求
repos.execute()
// 异步请求
repos.enqueue(new Callback(){...})
源码分析

下面就从这几个步骤切入,分析Retrofit内部的执行流程(笔者分析的版本是2.4.0),分析流程之前,我们先上结论,Retrofit的请求流程:

  1. Retrofit通过解析接口层定义的请求方法上的注解、参数信息来构造出Request请求对象
  2. 创建接口层的代理对象,来统一控制每个接口的访问,进而使每个接口访问最终走到了InvocationHandler#invoke方法中
  3. 通过网络请求适配器CallAdapter将网络请求对象进行平台适配(Android/Java8/Rxjava/Guava),来生成网络请求执行器
  4. 通过网络请求执行器来发送网络请求
  5. 通过数据转换器ConvertAdapter解析服务器返回的数据
  6. 通过对应平台的回调执行器CallbackExecutor将结果进行线程的调度(Android平台切换到主线程中)
  7. 客户端在对应线程中处理响应结果(Android平台在主线程中处理结果)

接口层定义我们的api接口,这个不用说了,根据Retrofit提供的相关注解来配置Server端的请求接口即可。

创建接口层的代理对象Retrofit#create(ApiService.class),我们先看下Retrofit对象的构建,内部是通过构建者模式构建Retrofit对象

public Builder() {
      this(Platform.get());
    }

    public Retrofit build() {
      // 必须指定baseUrl
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      // 如果没指定callFactory,则默认创建OkHttpClient    
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      // 回调执行器,将回调切换到主线程,本质就是利用了handler    
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
      // CallAdapter,请求执行器(发送网络请求)
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // ConvertAdapter,数据转换器(请求体的转换、响应体的转换)
      List<Converter.Factory> converterFactories =
          new ArrayList<>(1 + this.converterFactories.size());
      // 系统内置的放在第一个位置          
      converterFactories.add(new BuiltInConverters());
      // 添加我们定义的converterFactory
      converterFactories.addAll(this.converterFactories);
      // 构建Retrofit对象
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

Retrofit构建完成之后,然后就可以创建接口层的代理对象了,创建代码如下:

public <T> T create(final Class<T> 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 {
            // ...省略部分代码  
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

动态代理模式,这就就不再讲述了,这里通过动态代理,控制了所有接口方法的调用,就是说,每个接口方法调用都会走到这个invoke方法中,在这里我们可以实现统一控制,这种思路其实也可以想到,因为我们OkHttp发送网络请求可以抽象为以下几步:

  1. 构建Request
  2. 构建Call
  3. 执行Call

每个接口都是这种调用。那么我们就可以封装一个公共请求,对于不同的接口只是第一步构建Request不同,其它两步都是一样的。这里Retrofit其实也是这种思想。我们来具体分析:可以看到invoke方法中主要做了三件事:

  1. 将我们的请求方法包装成ServiceMethod
  2. 通过ServiceMethod和方法参数构建OkHttpCall
  3. 通过ServiceMethod将OkHttpCall进行代理包装
  • 分析ServiceMethod构建
ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

这里将ServiceMethod进行缓存

public ServiceMethod build() {
      // 拿到我们构建Retrofit时创建的CallAdapter,就是ExecutorCallbackCall它唯一做的事就是将原本Call的回调转发至主线程 
      callAdapter = createCallAdapter();
      // 拿到我们方法的实际返回类型,比如Call<User>
      responseType = callAdapter.responseType();
      // 对该类型进行判断
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      // 拿到响应体转换器,也是根据我们创建Retrofit时添加的ConverterFactory获取
      // 寻找的依据主要看该Converter能否处理你编写方法的返回值类型,默认实现为BuiltInConverters,仅仅支持返回值的实际类型为ResponseBody和Void,也就说明了默认情况下,是不支持Call<User>这类类型的。
      responseConverter = createResponseConverter();
      // 接下来就是对注解进行解析了,主要是对方法上的注解进行解析,那么可以拿到httpMethod以及初步的url(包含占位符)。    
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      if (httpMethod == null) {
        throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      if (!hasBody) {
        if (isMultipart) {
          throw methodError(
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
          throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }
      // 这里是对方法中参数中的注解进行解析,这一步会拿到很多的ParameterHandler对象
      // 该对象在toRequest()构造Request的时候调用其apply方法。    
      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);
      }

      if (relativeUrl == null && !gotUrl) {
        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError("Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError("Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError("Multipart method must contain at least one @Part.");
      }

      return new ServiceMethod<>(this);
    }

这里ServiceMethod主要用于将我们接口中的方法转化为一个Request对象,于是根据我们的接口返回值确定了responseConverter,解析我们方法上的注解拿到初步的url,解析我们参数上的注解拿到构建RequestBody所需的各种信息,最终调用toRequest的方法完成Request的构建。

  • 分析OkHttpCall的构建
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }

仅仅通过构造函数进行简单的赋值

  • 分析ServiceMethod#adapt(okHttpCall);
T adapt(Call<R> call) {
    return callAdapter.adapt(call);
  }

这里是直接调用CallAdapter的adapt()方法,这个CallAdapter之前构建Retrofit的时候已经创建了,就是ExecutorCallAdapterFactory.get()返回值

public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        // 返回值是ExecutorCallbackCall
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

可以看到adapt返回的是ExecutorCallbackCall对象,下面分析ExecutorCallbackCall

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) {
      checkNotNull(callback, "callback == null");

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

可以看出ExecutorCallbackCall仅仅是对Call对象进行封装,类似装饰者模式,只不过将其执行时的回调通过callbackExecutor进行回调到主线程中去了。

  • 分析Call的执行

在上面的分析中,我们已经拿到了ExecutorCallbackCall类型的Call对象,通过这个Call对象我们就可以直接调用enqueue进行异步请求了,看下源码的实现

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

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

可以看到通过callbackExecutor将回调切换到了主线程执行,但是实际的请求还是通过delegate完成的,这个delegate就是OkHttpCall对象。看下它的enqueue方法

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

    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }

    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

可以看到,它内部又是调用了okhttp3.Call的enqueue,相当于又封装了一层,接下来看下okhttp3.Call的创建

private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = serviceMethod.toCall(args);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }
/** Builds an HTTP request from method arguments. */
  okhttp3.Call toCall(@Nullable Object... args) throws IOException {
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
        contentType, hasBody, isFormEncoded, isMultipart);

    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args != null ? args.length : 0;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
    }

    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }

    return callFactory.newCall(requestBuilder.build());
  }

可以看到这里通过serviceMethod.toCall(args)先构造了Request对象,然后构造了Call对象,okhttp3.Call的enqueue方法中还涉及了一个parseResponse方法

@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
          // 解析响应
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

分析下parseResponse方法

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();
    // ...省略部分代码
    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }

可以看到这里通过serviceMethod对ResponseBody进行转化,然后返回,转化实际上就是通过responseConverter的convert方法。

 /** Builds a method return value from an HTTP response body. */
  R toResponse(ResponseBody body) throws IOException {
    // 通过转换器进行数据转换
    return responseConverter.convert(body);
  }
自定义Converter.Factory

源码中Converter.Factory定义如下:

  abstract class Factory {
  
    // 响应体的转换
    public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
        Annotation[] annotations, Retrofit retrofit) {
        // !!!这里根据type判断是否是自己能处理的类型,不能的话,一定要return null,交给后面的Converter.Factory
      return null;
    }

    // 请求体的转换
    public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
        Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        // 逻辑实现
      return null;
    }
    ...省略部分代码
  }

主要是实现请求体的转换,和响应体的转换。
添加Converter.Factory的方法为addConverterFactory

 Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.example.com/")
                //.addConverterFactory(GsonConverterFactory.create())
                .build();

源码中已经定义了一个内置的转换器,BuiltInConverters,这里就不分析了,可以直接看下源码,我们看下拓展库GsonConverterFactory的实现

public final class GsonConverterFactory extends Converter.Factory {
  
  public static GsonConverterFactory create() {
    return create(new Gson());
  }

  public static GsonConverterFactory create(Gson gson) {
    return new GsonConverterFactory(gson);
  }
  // 构建了一个Gson对象    
  private final Gson gson;

  private GsonConverterFactory(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    this.gson = gson;
  }

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    // 构建Gson的响应转换器
    return new GsonResponseBodyConverter<>(gson, adapter);
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    // 构建Gson的请求转换器
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }
}

源码很简单,就是实现了对象->json字符串以及json字符串->对象的映射。

reqeustBodyConverter 主要是对应@Body注解,完成对象到RequestBody的转化,其实@Part等注解也会需要responseBodyConverter,只不过我们的参数类型都是RequestBody,由默认的converter处理了。

resposneBodyConverter主要对应响应数据到返回类型的转换,这个类型对应Call&lt;XXX&gt;里面的泛型XXX,一定要注意,检查type如果不是自己能处理的类型,记得return null (因为可以添加多个,你不能处理return null ,还会去遍历后面的converter

思考与感悟
  • Retrofit非常巧妙的利用注解来描述一个HTTP请求,它将一个HTTP请求抽象为一个接口方法,然后通过动态代理的方式将一个方法注解参数等信息翻译成一个具体的HTTP请求,最后执行这个请求
  • Retrofit利用了大量的设计模式,如工厂、适配器、代理、外观、适配器等。
  • Retrofit的可配置性非常强,比如开放了数据转换器接口、网络执行器接口,客户端可以根据需求自我实现
  • Platform平台的设计,Retrofit内部根据类加载的思路确定当前的运行环境,从而配置不同的执行
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值