源码面前无秘密之——Retrofit 源码分析

本文主要通过Retrofit的简单使用,来分析使用Retrofit的大致过程,通过分析分析源码来了解一下它的秘密。

一.Retrofit 简单使用

1. 导入依赖

implementation 'com.squareup.retrofit2:retrofit:2.8.1'

下面分析的Retrofit版本也是2.8.1

2.创建API方法接口

interface ApiService {
    //普通版
    @GET("article/list/{page}/json")
    fun getArticleList(@Path("page") page: Int): Call<Result<PageEntity<Article>>>
    //java 8支持
    @GET("article/list/{page}/json")
    fun getArticleList1(@Path("page") page: Int): CompletableFuture<Result<PageEntity<Article>>>
    //使用kotlin协程
    @GET("article/list/{page}/json")
    suspend fun getArticleList2(@Path("page") page: Int): Result<PageEntity<Article>>

}

下面分析主要以普通版为主,其他类似,关于kotlin协程的支持可以看看我之前写的另一篇文章kotlin 协程在 Android 中的使用——Jetpack 中的协程、Retofit中使用协程及源码分析 文中有相关代码分析

3. 使用retrofit 异步请求

val retrofit=  Retrofit.Builder()
      .baseUrl("https://www.wanandroid.com")
      .addConverterFactory(GsonConverterFactory.create(GsonBuilder().enableComplexMapKeySerialization().create()))
      .build()

  val api = retrofit.create(ApiService::class.java)
  api.getArticleList(1).enqueue(object :Callback<Result<PageEntity<Article>>>{
      override fun onFailure(call: Call<Result<PageEntity<Article>>>, t: Throwable) {
          Log.i("main","failure")
      }

      override fun onResponse(
          call: Call<Result<PageEntity<Article>>>,
          response: Response<Result<PageEntity<Article>>>
      ) {
          Log.i("main","onResponse")
      }
  })

以下分析以getArticleList()方法为主

二 、源码分析

1.流程分析


下面就沿着getArticleList方法看一下Retrofit如何执行的,当我们调用enqueue方法时发起异步请求,点击enqueue方法发现是一个 接口方法,getArticleList是我们定义的接口方法也没有具体实现,那我看个鬼代码呀,洗洗睡了 return。
哈哈,睡不着还是看看代码吧,我们在分析分析,我们定义的接口实例对象是通过retrofit.create(ApiService::class.java)创建的,那就看看这个create方法吧,点击查看create方法,发现这里有具体的实现代码,那么就看是从这里看吧。

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.
            //如何这个方法是父类(Object)的方法,那就直接执行,eg. toString()
          if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
          }
           //java 8 接口也可以有默认实现,如何有默认实现,就直接执行默认实现
          if (platform.isDefaultMethod(method)) {
            return platform.invokeDefaultMethod(method, service, proxy, args);
          }
          return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
        }
      });
}

这个方法主要时利用动态代理 Proxy.newProxyInstance

/**
* @params loader 类加载器
* @params interfaces  需要代理的接口数组
* @params h  InvocationHandler 是一个回调接口,有个invoke方法,每当调用代理接口的方法时,
*   		invoke都会被调用
**/
public static Object newProxyInstance(ClassLoader loader,
                                    Class<?>[] interfaces,
                                    InvocationHandler h)
  throws IllegalArgumentException


当我们调用接口方法是时候,invoke 就会被调用,该方法最后一行调用的loadServiceMethod 然后在调用它的invoke方法并将返回值return,点击进入它的invoke方法,发现是个抽象方法,那就先放着吧,先看loadServiceMethod方法干了啥

ServiceMethod<?> loadServiceMethod(Method method) {
//serviceMethodCache是ConcurrentHashMap<>() 用来缓存解析后的方法相关值
  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;
}


上面loadServiceMethod 返回的是一个ServiceMethod对象,这个有什么用, 我们在看看ServiceMethod.parseAnnotations方法吧


ServiceMethod.java

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    //解析注解<1>
  RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

  Type returnType = method.getGenericReturnType();
  if (Utils.hasUnresolvableType(returnType)) {
    throw methodError(method,
        "Method return type must not include a type variable or wildcard: %s", returnType);
  }
  if (returnType == void.class) {
    throw methodError(method, "Service methods cannot return void.");
  }

  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

RequestFactory 通过 parseAnnotations 通过建造者模式,从 retrofit 和method对象中解析中一些值保存到RequestFactory 对象中,我们定义的注解就是在这解析处理的

private final Method method;
private final HttpUrl baseUrl;
final String httpMethod; //通过解析注解获取 eg. GET 、POST
private final @Nullable String relativeUrl;//相对地址 @GET("list")
private final @Nullable Headers headers;
private final @Nullable MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
final boolean isKotlinSuspendFunction;//是否是kotlin suspend函数


parseAnnotations 方法的最后调用了,HttpServiceMethod.parseAnnotations,我们在去看看这个方法干了啥


妈呀这个方法好多行@_@。让我先看看

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
        //是否是kotlin suspend 函数
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    // -------------start 获取adapterType-------------------------
     //是kotlin suspend 函数,可以略过这个细节,先看最普通情况流程怎么走
    if (isKotlinSuspendFunction) {
        //获取参数类型,包括泛型的参数
      Type[] parameterTypes = method.getGenericParameterTypes();
        //获取suspend 最后一个参数,suspend函数编译后,会在原来的参数后面多一个参数
        //这个参数是kotlin.coroutines.Continuation<函数返回值类型>
      Type responseType = Utils.getParameterLowerBound(0,
          (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
          //判断函数返回值是否是Response
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      } else {
        // TODO figure out if type is nullable or not
        // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
        // Find the entry for method
        // Determine if return type is nullable or not
      }
      //将返回值类型外面包裹一层Call eg. Call<函数返回值类型>
      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      adapterType = method.getGenericReturnType();
    }
     // ---------------end -----------------------

     //根据adapterType创建CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    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)");
    }
    // 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);
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {//不是suspend 返回一个CallAdapted对象
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
          continuationBodyNullable);
    }
  }


代码有点多,因为2.6.0版本加入了对kotlin协程的支持,多了一些分支判断,我们按照getArticleList方法调用走的流程,来简化一下上面的方法如下


HttpServiceMethod.java

  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
   //kotlin suspend 方式代码省略
    Type adapterType;
    adapterType = method.getGenericReturnType();
     //1. 根据adapterType创建CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    // 省略responseType合法性判断

    //2. 创建responseConverter,
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    //3. 返回 CallAdapted(HttpServiceMethod)//kotlin suspend 省略
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  }


到此为止,通过loadServiceMethod(Method method)方法得到的对象是类型是CallAdapted


在上面InvocationHandlerinvoke 的方法最后一句执行的是

return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);


现在我们知道了,在上述情况分析下 loadServiceMethod(method)得到的是CallAdapted的对象,那么我们就去CallAdapted 类中看看invoke 方法吧,但是发现并没有此方法。CallAdapted 继承自HttpServiceMethod 我们在这个类中找到了invoke方法

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


该方法最后调用了adapt 方法,它是抽象方法,由它的子类CallAdapted 实现

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


那这个callAdapter是什么??它是通过CallAdapted构造方法参数传入来的。那我们就要回到CallAdapted 创建对象的时候,看看传入的callAdapter是什么,那就要回到HttpServiceMethod.java 的parseAnnotations方法再看一看,发现callAdapter 是通过下面这行代码等到的

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


这个方法追踪下去会看到这个方法


Retrofit.java

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
    Annotation[] annotations) {
  Objects.requireNonNull(returnType, "returnType == null");
  Objects.requireNonNull(annotations, "annotations == null");

  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通过build创建对象时就准备好的,然后根据returnType, annotations来找到合适的adapter。下面是Retrofit 的build方法中关于callAdapterFactories的部分代码

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

// 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));
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
    @Nullable Executor callbackExecutor) {
  DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
  return hasJava8Types
      ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
      : singletonList(executorFactory);
}


从上面我们可以知道,在Retrofit 通过build()构建对象时,如果是java8 那么callAdapterFactories集合中的元素有CompletableFutureCallAdapterFactory 和DefaultCallAdapterFactory 两个类的对象。如何不是java8 那就只有DefaultCallAdapterFactory 这一个元素。
那现在再回到nextCallAdapter的方法,看看最终返回的的是那个adapter。CompletableFutureCallAdapterFactory 的get方式是这样的

@Override public @Nullable CallAdapter<?, ?> get(
    Type returnType, Annotation[] annotations, Retrofit retrofit) {
  if (getRawType(returnType) != CompletableFuture.class) {
    return null;
  }
    //省略代码
}


如果返回值不是CompletableFuture.class就返回null,我们上面getArticleList的返回值是Call 显示不是这个


那在看看DefaultCallAdapterFactory 的get方法

@Override public @Nullable CallAdapter<?, ?> get(
    Type returnType, Annotation[] annotations, Retrofit retrofit) {
  if (getRawType(returnType) != Call.class) {
    return null;
  }
  if (!(returnType instanceof ParameterizedType)) {
    throw new IllegalArgumentException(
        "Call return type must be parameterized as Call or Call");
  }
  final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

  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) {
      return executor == null
          ? call
          : new ExecutorCallbackCall<>(executor, call);
    }
  };
}


我们写的方法符合这个,所以我们callAdapter 对象是通过DefaultCallAdapterFactory 的get方法得到的,他的adapt方法返回值是new ExecutorCallbackCall<>(executor, call)到此为止我们知道了当我们调用getArticleList方法会经过上面一系列的过程,最终返回ExecutorCallbackCall对象。


上面我们getArticleList的方法的返回值调用enqueue方法发起了异步回调。那么ExecutorCallbackCall这个类中应该有我们想看到的enqueue方法实现,下面就是它的代码

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

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


上面delegate是什么鬼,它是 retrofit2.Call 类型的它是ExecutorCallbackCall<>(executor, call)创建对象通过构造方法传入过来的。那这个call对象是从那么传入来的呢。我们验证它的传入往上找一找,发现是在HttpServiceMethod.java 的invoke方法中创建的

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

所以上面delegate就是这个OkHttpCall,在它的enqueue里面,会创建一个Okhttp的Call对象,利用OkHttp发起网络请求,Retrofit把网络数据转换成相应的对象就是在这里操作的。


再点击OkHttpCall类中查看它的enqueue方法如下

@Override public void enqueue(final Callback<T> callback) {
  Objects.requireNonNull(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) {
        throwIfFatal(e);
        callFailure(e);
        return;
      }

      try {
        callback.onResponse(OkHttpCall.this, response);
      } catch (Throwable t) {
        throwIfFatal(t);
        t.printStackTrace(); // TODO this is not great
      }
    }

    @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) {
        throwIfFatal(t);
        t.printStackTrace(); // TODO this is not great
      }
    }
  });
}


因为Retrofit是对OKHttp 的封装,所以这个方法里面可以看到它创建了一个okhttp的Call 然后调用他来实现的异步网络请求,到此一个完整的网络请求流程就走完了。

2.大致的流程图


下面是使用Retrofit发起网络请求的大致流程

源码面前无秘密之——Retrofit 源码分析_第1张图片

三总结时刻


1.Retrofit通过Build 模式创建对象,Retrofit相当于一个配置管理,里面有要请求的baseUrl、用于发起网络请求的CallAdapter的工厂集合([DefaultCallAdapterFactory])、还有用于转换网络数据格式的Converter.Factory集合,例如上面实例代码利用Gson转换工厂。


2.定义Retrofit网络请求方法,只需要定义接口,使用相关注解。通过create()方法创建接口实例,当我们调用方法时,会进行注解解析等工作,这个比较耗时,所以他有缓存机制,就像上图灰色区域。


3 通过ServiceMethod对象调用invoke方法得到Call对象,是通过Retrofit对象中的合适的CallAdapter的工厂创建的,当调用Call对象的enqueue时,是通过Okhttp发起请求,当请求成功后通过数据转换工厂Converter.Factory转换为相应的数据,然后调用retrofit2.Callback回调。
好了我对Retrtofit的源码分析就到此结束 ,睡觉。

你可能感兴趣的:(Android)