Retrofit源码分析(超详细)

作者: gatsby_dhn | 来源:发表于2016-10-03 08:40 被阅读5468次

    Retrofit是对OKHttp的封装,简化了网络请求。具体使用参见官方文档。本文从一次完整的同步请求分析源码,跟着源码一起阅读,肯定会有收获的。分析的版本是retrofit-2.1.0

    支持原创,转载请注明出处。

    老规矩,先上图。

    类图

    Retrofit.png

    实例

    public class LearnRetrofit {
        public static final String API_URL = "https://api.github.com";
    
          //创建接口
          public interface GitHub {
            @GET("/repos/{owner}/{repo}/contributors")
            Call<ResponseBody> contributors(
                @Path("owner") String owner,
                @Path("repo") String repo);
          }
    
          public static void main(String[] args) throws IOException {
            //创建Retrofit对象
            Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(API_URL)
                .build();
    
            //动态生成一个代理对象
            GitHub github = retrofit.create(GitHub.class);
    
            //生成一个OKHttpCall的代理对象
            Call<ResponseBody> call = github.contributors("square", "retrofit");
    
            //返回结果
            Response<ResponseBody> response = call.execute();
            
            //打印数据
            System.out.println(response.body().string());
          }
    }
    
    

    我们从官方文档里的一个例子开始。我做了一些修改,开始不使用GsonConverter对结果进行转换,后面会添加,在默认情况下Retrofit只支持将HTTP的响应体转换换为ResponseBody(OKHttp中的类),默认情况下Retrofit使用BuiltInConverters这个默认的Converter,后面会再次提到。第一步,创建一个接口。第二步,创建一个Retrofit对象,提供BASE_URL等信息。第三步,创建一个实现了接口的代理对象。第四步,调用接口方法,返回一个Call对象。第五步,调用execute执行同步请求。第六步,从响应获取数据。我们跟着步骤一步一步分析。

    创建Call

      public <T> T create(final Class<T> service) {
        Utils.validateServiceInterface(service);
        if (validateEagerly) {
          eagerlyValidateMethods(service);
        }
        //Proxy.newProxyInstance()返回一个Github的代理类对象
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
              private final Platform platform = Platform.get();
    
              //这个invoke方法会在代理对象的方法中调用,第一个参数就是代理对象
              //第二个参数是代理对象调用的方法
              //第三个参数方法的参数
              @Override public Object invoke(Object proxy, Method method, 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);
                }
               //调用loadMethodHandler
                return loadMethodHandler(method).invoke(args);
              }
            });
      }
    

    这里使用了动态代理,Proxy.newProxyInstance()返回一个Github的代理类对象。当我们调用github这个代理对象的方法比如contributors()时,会调用调用上述的invoke方法,第一个参数就是代理对象,第二个参数是代理对象调用的方法,第三个参数是方法的参数。动态代理可以看我以前的写的文章,建议完全搞懂动态代理,然后往下看。假设现在我调用了github.contributors("square", "retrofit")那么会调用invoke方法,然后调用loadMethodHandler()方法。

      MethodHandler loadMethodHandler(Method method) {
        MethodHandler handler;
        synchronized (methodHandlerCache) {
          handler = methodHandlerCache.get(method);
          if (handler == null) {
            //创建MethodHandler 对象
            handler = MethodHandler.create(this, method);
            methodHandlerCache.put(method, handler);
          }
        }
        return handler;
      }
    

    loadMethodHandler()返回一个MethodHandler对象,然后调用这个对象的invoke()方法。我们看下这个类。

    //核心成员变量
      private final okhttp3.Call.Factory callFactory;
      private final RequestFactory requestFactory;
      private final CallAdapter<?> callAdapter;
      private final Converter<ResponseBody, ?> responseConverter;
    
    //核心方法
      static MethodHandler create(Retrofit retrofit, Method method) {
        //创建CallAdapter
        CallAdapter<?> callAdapter = createCallAdapter(method, retrofit);
        Type responseType = callAdapter.responseType();
        if (responseType == Response.class || responseType == okhttp3.Response.class) {
          throw Utils.methodError(method, "'"
              + Types.getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
        }
       //创建Converter
        Converter<ResponseBody, ?> responseConverter =
            createResponseConverter(method, retrofit, responseType);
        RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit);
        return new MethodHandler(retrofit.callFactory(), requestFactory, callAdapter,
            responseConverter);
      }
    
    //创建CallAdapter
      private static CallAdapter<?> createCallAdapter(Method method, Retrofit retrofit) {
        Type returnType = method.getGenericReturnType();
        if (Utils.hasUnresolvableType(returnType)) {
          throw Utils.methodError(method,
              "Method return type must not include a type variable or wildcard: %s", returnType);
        }
        if (returnType == void.class) {
          throw Utils.methodError(method, "Service methods cannot return void.");
        }
        Annotation[] annotations = method.getAnnotations();
        try {
          //调用Retrofit.callAdapter()
          return retrofit.callAdapter(returnType, annotations);
        } catch (RuntimeException e) { // Wide exception range because factories are user code.
          throw Utils.methodError(e, method, "Unable to create call adapter for %s", returnType);
        }
      }
    
    //创建Converter
      private static Converter<ResponseBody, ?> createResponseConverter(Method method,
          Retrofit retrofit, Type responseType) {
        Annotation[] annotations = method.getAnnotations();
        try {
          //调用Retrofit.responseBodyConverter()方法
          return retrofit.responseBodyConverter(responseType, annotations);
        } catch (RuntimeException e) { // Wide exception range because factories are user code.
          throw Utils.methodError(e, method, "Unable to create converter for %s", responseType);
        }
      }
    

    在创建MethodHandler这个类的时候,我要创建一个CallAdapter和一个Converter,从流程看,分别调用retrofit.callAdapter(returnType, annotations);retrofit.responseBodyConverter(responseType, annotations);创建。Retrofit的这两个方法最终调用如下两个方法。

      public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
          Annotation[] annotations) {
        checkNotNull(returnType, "returnType == null");
        checkNotNull(annotations, "annotations == null");
    
        int start = adapterFactories.indexOf(skipPast) + 1;
        for (int i = start, count = adapterFactories.size(); i < count; i++) {
          //从adapterFactories这个LIst获取
          CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
          if (adapter != null) {
            return adapter;
          }
        }
    
        StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
            .append(returnType)
            .append(".\n");
        if (skipPast != null) {
          builder.append("  Skipped:");
          for (int i = 0; i < start; i++) {
            builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
          }
          builder.append('\n');
        }
        builder.append("  Tried:");
        for (int i = start, count = adapterFactories.size(); i < count; i++) {
          builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
        }
        throw new IllegalArgumentException(builder.toString());
      }
    
    
    
      public <T> Converter<T, RequestBody> nextRequestBodyConverter(Converter.Factory skipPast,
          Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {
        checkNotNull(type, "type == null");
        checkNotNull(parameterAnnotations, "parameterAnnotations == null");
        checkNotNull(methodAnnotations, "methodAnnotations == null");
    
        int start = converterFactories.indexOf(skipPast) + 1;
        for (int i = start, count = converterFactories.size(); i < count; i++) {
          //从converterFactories这个List获取
          Converter.Factory factory = converterFactories.get(i);
          Converter<?, RequestBody> converter =
              factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this);
          if (converter != null) {
            //noinspection unchecked
            return (Converter<T, RequestBody>) converter;
          }
        }
    
        StringBuilder builder = new StringBuilder("Could not locate RequestBody converter for ")
            .append(type)
            .append(".\n");
        if (skipPast != null) {
          builder.append("  Skipped:");
          for (int i = 0; i < start; i++) {
            builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
          }
          builder.append('\n');
        }
        builder.append("  Tried:");
        for (int i = start, count = converterFactories.size(); i < count; i++) {
          builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
        }
        throw new IllegalArgumentException(builder.toString());
      }
    

    这两个方法分别从adapterFactories和converterFactories获取一个CallAdapter和Converter,我们看下这两个List是如何构造的。

        public Retrofit build() {
          if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
          }
    
          okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) {
            callFactory = new OkHttpClient();
          }
    
          // 创建List保存CallAdapter.Factory
          List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
          //添加一个默认的CallAdapterFactory
        adapterFactories.add(Platform.get().defaultCallAdapterFactory(callbackExecutor));
    
          // 创建List保存Converter.Factory
          List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    
          return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
              callbackExecutor, validateEagerly);
        }
    
    
        public Builder() {
          // Add the built-in converter factory first. This prevents overriding its behavior but also
          // ensures correct behavior when using converters that consume all types.
         //添加默认的ConverterFactory
          converterFactories.add(new BuiltInConverters());
        }
    

    如果我们在构造Retrofit时没有提供CallAdaCallAdapter.Factory和Converter.Factory,构造时会使用默认值,我看看下代码

    //添加默认CallAdapterFactory
    adapterFactories.add(Platform.get().defaultCallAdapterFactory(callbackExecutor));   
    
    //最终是这个类
    final class DefaultCallAdapterFactory extends CallAdapter.Factory {
      static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
    
      @Override
      public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
          return null;
        }
    
        final Type responseType = Utils.getCallResponseType(returnType);
        //返回匿名CallAdapter类
        return new CallAdapter<Call<?>>() {
          @Override public Type responseType() {
            return responseType;
          }
    
          @Override public <R> Call<R> adapt(Call<R> call) {
            return call;
          }
        };
      }
    }
    

    我们看到DefaultCallAdapterFactory生成的匿名CallAdapter类的adapt方法把call原封不动得传回。再来看看RequestBodyConverter。

      static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
        static final RequestBodyConverter INSTANCE = new RequestBodyConverter();
        
         //将RequestBody原封不动返回,不做任何处理
        @Override public RequestBody convert(RequestBody value) throws IOException {
          return value;
        }
      }
    

    好了,到这里我们总结下,我们创建了一个MethodHandler对象,创建过程中,我们又创建了一个默认的CallAdapter和一个默认的RequestBodyConverter 。创建完了MethodHandler,我们调用了它的invoke()方法。

      Object invoke(Object... args) {
        return callAdapter.adapt(
            new OkHttpCall<>(callFactory, requestFactory, args, responseConverter));
      }
    

    这里使用了我们刚才创建的默认的CallAdapter,上面我们知道它的adapt()仅仅是返回参数,其他什么都不做。所以这里返回的是一个OkHttpCall对象。这个OkHttpCall实现了Call<T>接口。我们总结下,到现在为止,我们仅仅调用了这两句

    //动态生成一个代理对象
    GitHub github = retrofit.create(GitHub.class);
    
    //生成一个OKHttpCall的代理对象
    Call<ResponseBody> call = github.contributors("square", "retrofit");
    

    所以我们知道Call<ResponseBody> call = github.contributors("square", "retrofit")返回的就是OkHttpCall对象。接下来我们应该调用Response<ResponseBody> response = call.execute();,我们看下OkHttpCall的execute方法。

    调用call.execute()

    final class OkHttpCall<T> implements Call<T> {
    //核心成员变量
      private final okhttp3.Call.Factory callFactory;
      private final RequestFactory requestFactory;
      private final Object[] args;
      private final Converter<ResponseBody, T> responseConverter;
    
    //核心方法
      @Override public Response<T> execute() throws IOException {
        okhttp3.Call call;
    
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already executed.");
          executed = true;
    
          if (creationFailure != null) {
            if (creationFailure instanceof IOException) {
              throw (IOException) creationFailure;
            } else {
              throw (RuntimeException) creationFailure;
            }
          }
    
          call = rawCall;
          if (call == null) {
            try {
               //将任务抛给OKHttp
              call = rawCall = createRawCall();
            } catch (IOException | RuntimeException e) {
              creationFailure = e;
              throw e;
            }
          }
        }
    
        if (canceled) {
          call.cancel();
        }
       
        //转换结果
        return parseResponse(call.execute());
      }
    
     //生成okhttp3.Call
      private okhttp3.Call createRawCall() throws IOException {
        //这个callFactory就是OKHttpClient
        okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
        if (call == null) {
          throw new NullPointerException("Call.Factory returned null.");
        }
        return call;
      }
    
     //将okhttp3.Response转换成Response
      Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
        ResponseBody rawBody = rawResponse.body();
    
        // Remove the body's source (the only stateful object) so we can pass the response along.
        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.
            ResponseBody bufferedBody = Utils.buffer(rawBody);
            return Response.error(bufferedBody, rawResponse);
          } finally {
            rawBody.close();
          }
        }
    
        if (code == 204 || code == 205) {
          return Response.success(null, rawResponse);
        }
    
        ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
        try {
          //这个responseconverter就是默认提供的RequestBodyConverter,当然我们可以替换成自己的converter比如GsonConverter
          T body = responseConverter.convert(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;
        }
      }
    

    好了,再次总结下,我们调用了OKHttpCall.execute(),该方法生成一个okhttp3.Call将任务抛给OKHttp,完了调用parseResponse,用Converter将okhttp3.Response转换成我们在范型中指定的类型Response<ResponseBody> response = call.execute(),我指定了okhttp3.ResonseBody。然后返回结果。如果我在构造Retrofit时提供了GsonConverter,addConverterFactory(GsonConverterFactory.create())那么上面的T body = responseConverter.convert(catchingBody);responseConverter就是GsonConverter。

    总结

    Retrofit就是对OkHttp的包装,了解原理后我们将更好地使用它。

    如果觉得写得还不错可以关注我哦,后面会将更多笔记的内容整理成博客。
    支持原创,转载请注明出处。

    相关文章

      网友评论

      本文标题:Retrofit源码分析(超详细)

      本文链接:https://www.haomeiwen.com/subject/ytndyttx.html