【源码解读】Retrofit网络请求过程源码解析

之前写了一个Gank.io的客户端练手学习了下RxJava+Retrofit的基本使用,顺着代码看了下相关的源码,将分析笔记记录于此,欢迎有兴趣的小伙伴多多指正,共同进步。

在写Gank的过程中,查看妹子福利时的代码如下,从创建接口到访问网络数据再到转换数据,RxJava+Retrofit到底是怎么完成的呢?

public interface GankApi {
  @GET("data/福利/{number}/{page}")
  Observable<GankGirlResult> getGirls(@Path("number") int number, @Path("page") int page);
}
//1.创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
               .client(okHttpClient)
               .baseUrl(baseUrl)
               .addConverterFactory(gsonConverterFactory)
               .addCallAdapterFactory(rxJavaCallAdapterFactory)//4
               .build();//5
//2.构造请求接口
gankApi = retrofit.create(GankApi.class);
//3.执行请求
gankApi.getGirls(10, page++)

按照代码我们的分析也分成了三块:Retrofit对象的创建、GankApi请求接口的生成、执行网络请求的调用。

一、Retrofit对象的创建

Retrofit采用Builder模式创建,首先从Builder开始看起,先是初始化平台对象,并向集合converterFactories中默认添加了一个BuiltInConverters对象

Builder(Platform platform) {
      this.platform = platform;
      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
    }
1.client(okHttpClient)与baseUrl(baseUrl)

我们知道Retrofit本质上还是利用OkHttp进行网络访问,这一步就是提供一个okHttpClient对象用来发送请求,同时设置请求地址的基本路径。如果不设置则会报异常。

2.addConverterFactory与addCallAdapterFactory

这一步指定使用Gson对返回数据进行解析,使用RxJava进行回调,具体创建操作后面再进行分析。

public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      adapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }
3.build()

这里就是基于Builder创建Retrofit的代码,主要信息都在注释里面了。

public Retrofit build() {

    //1.如果没有设置baseUrl则抛出异常
    if (baseUrl == null) {
      throw new IllegalStateException("Base URL required.");
    }
    //2.如果没有设置OkHttpClient对象则进行设置
    okhttp3.Call.Factory callFactory = this.callFactory;
    if (callFactory == null) {
      callFactory = new OkHttpClient();
    }
    //3.如果没有设置Executor则根据平台设置默认的Executor
    Executor callbackExecutor = this.callbackExecutor;
    if (callbackExecutor == null) {
      callbackExecutor = platform.defaultCallbackExecutor();
    }

    //4.基于Executor创建默认的CallAdapter.Factory,这里具体就是ExecutorCallAdapterFactory对象
    List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
    adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
        callbackExecutor, validateEagerly);
  }

上面就是其Retrofit的对象的构建过程,基本就是设置了OkHttpClient和基础路径,然后设置Converter.Factory和CallAdapter.Factory。有一点区别是Converter.Factory的集合在我们设置GsonConvert之前就添加了一个元素BuiltInConverters,而对于CallAdapter.Factory则是在设置完成后添加的。对于构建完成后的两个集合如下(偷懒直接断点截了个图,捂脸):

这里写图片描述

下面是我们关注的重点,其create方法创建我们想要的Api类以及方法的调用

二、请求接口的生成

通过下面的create方法的代码我们可以看出Retrofit是通过动态代理来创建调用我们的请求方法的,首先将调用的Method解析为ServiceMethod,
然后封装为OkHttpCall请求对象,最后通过CallAdapter执行请求返回数据。这一部分我们重点分析ServiceMethod的创建。

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, Object... args)
              throws Throwable {
            //...代码省略

            //1.将Method解析为ServiceMethod对象
            ServiceMethod serviceMethod = loadServiceMethod(method);
            //2.将ServiceMethod和args参数封装为OkHttpCall对象
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //3.发送请求返回封装好的Call对象,如果是RxJava作为Adapter则返回Observable对象
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }
1.将Method封装为ServiceMethod对象
  public Builder(Retrofit retrofit, Method method) {
     this.retrofit = retrofit;、
     this.method = method;
     this.methodAnnotations = method.getAnnotations();//获取方法的注解数组
     this.parameterTypes = method.getGenericParameterTypes();//获取形参数据
     this.parameterAnnotationsArray = method.getParameterAnnotations();//获取形参的注解
   }

   public ServiceMethod build() {
      //1.创建CallAdapter对象,并获取响应的数据类型,其实我们要转换的数据类型
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      //2.创建Converter对象
      responseConverter = createResponseConverter();
      //3.解析方法注解
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      //4.解析参数注解
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      return new ServiceMethod<>(this);
    }

上面是去掉各种异常处理之后的简化代码,其主要做了四项操作。
下面来看下四步的代码(具体到细节的话每一步都可以写成一篇文章,因此这里只做简单分析):

  • CallAdapter的创建

    最终调用的是Retrofit中的nextCallAdapter。
    上面提到了,在构建Retrofit时,使用List集合存放CallAdapter.Factory,RxJavaCallAdapterFactory存放于0,默认的DefaultCallAdapterFactory或者ExecutorCallAdapterFactory存放于1,因此在创建CallAdapter时如果设置了RxJavaCallAdapterFactory优先使用RxJavaCallAdapterFactory创建Adapter。

//adapterFactories集合,默认skipPast为null,因此indexOf返回-1,start从0开始,遍历第一个就是RxJavaCallAdapterFactory
  //使用该对象创建CallAdapter对象,
  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++) {
     CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
     if (adapter != null) {
       return adapter;
     }
   }
 }

下面是RxJavaCallAdapterFactory的get方法具体的代码,returnType参数就是我们所调用方法的返回值类型

@Override
 public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
   Class<?> rawType = getRawType(returnType);
   //获取全类名为rx.Observable因此isSingle与isCompletable均为false,最终调用getCallAdapter方法来获取对象
   //具体细节这里不再分析,这里最终返回的是SimpleCallAdapter类的对象。
   String canonicalName = rawType.getCanonicalName();
   boolean isSingle = "rx.Single".equals(canonicalName);
   boolean isCompletable = "rx.Completable".equals(canonicalName);
   if (rawType != Observable.class && !isSingle && !isCompletable) {
     return null;
   }

   if (isCompletable) {
     return CompletableHelper.createCallAdapter(scheduler);
   }

   CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler);
   if (isSingle) {
     return SingleHelper.makeSingle(callAdapter);
   }
   return callAdapter;
 }

PS:RxJavaCallAdapterFactory提供了ResponseCallAdapter、SimpleCallAdapter、ResultCallAdapter三种Adapter,具体细节区别有兴趣的同学可以研究下源码。

  • Converter的创建
    和存储RxJavaCallAdapterFactory的集合相反,存储Converter对象的集合第一个存储的是BuiltInConverters对象,其次存储的是我们的GsonConverterFactory,最终调用的是Retrofit中的nextResponseBodyConverter方法
    其创建方法如下:
  public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
     Type type, Annotation[] annotations) {
   checkNotNull(type, "type == null");
   checkNotNull(annotations, "annotations == null");
   //start为0
   int start = converterFactories.indexOf(skipPast) + 1;

   for (int i = start, count = converterFactories.size(); i < count; i++) {
     //首先遍历到的是BuiltInConverters,这时的返回类型就是我们定义方法里面的类型,BuiltInConverters的responseBodyConverter返回null。第二次遍历是GsonConverterFactory的GsonResponseBodyConverter,直接返回GsonResponseBodyConverter对象,
     Converter<ResponseBody, ?> converter =
         converterFactories.get(i).responseBodyConverter(type, annotations, this);
     if (converter != null) {
       //noinspection unchecked
       return (Converter<ResponseBody, T>) converter;
     }
   }

 }
 //创建GsonResponseBodyConverter
 @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }
  • 解析方法注解和参数注解
    解析方法注解,下面是我摘取的部分方法代码,可以看到我们很熟悉的GET和POST请求注解的解析,也包括http和head的解析。我们创建网络接口上的注解就是在这里进行解析的。
private void parseMethodAnnotation(Annotation annotation) {

      if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
        if (!Void.class.equals(responseType)) {
          throw methodError("HEAD method must use Void as response type.");
        }
      }  else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      }
    }

对于参数注解的解析,首先遍历每一个参数的每一个注解,然后对每个参数的注解构造ParameterHandler对象。具体细节这里不再赘述
上述操作完成后就完成了ServiceMethod的构建。

三、执行请求

在构建请求完成后就是调用我们的方法了,具体到我们的代码就是调用了SimpleCallAdapter的adapt方法:

@Override public <R> Observable<R> adapt(Call<R> call) {
   Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) //1.将call传递给CallOnSubscribe,执行网络请求
       .flatMap(new Func1<Response<R>, Observable<R>>() {//2.对数据进行转换成函数所需要的Obserable对象,
         @Override public Observable<R> call(Response<R> response) {
           if (response.isSuccessful()) {
             return Observable.just(response.body());
           }
           return Observable.error(new HttpException(response));
         }
       });
  //
   if (scheduler != null) {
     return observable.subscribeOn(scheduler);
   }
   return observable;

可以看到,首先是将call传递给了CallOnSubscribe。这是RxJavaCallAdapterFactory的一个内部类,简化后的代码如下

  static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
    private final Call<T> originalCall;

    CallOnSubscribe(Call<T> originalCall) {
      this.originalCall = originalCall;
    }

    @Override public void call(final Subscriber<? super Response<T>> subscriber) {
      // Since Call is a one-shot type, clone it for each new subscriber.
      final Call<T> call = originalCall.clone();

      // Attempt to cancel the call if it is still in-flight on unsubscription.
      subscriber.add(Subscriptions.create(new Action0() {
        @Override public void call() {
          call.cancel();
        }
      }));
        //执行网络请求
        Response<T> response = call.execute();
        if (!subscriber.isUnsubscribed()) {
          subscriber.onNext(response);
        }
    }
  }

可以看到是在CallOnSubscribe的call方法中执行了网络请求execute()并将Response对象作为参数通过flatMap转换为相应的Observable对象,也就是我们的接口方法的返回类型Observable,剩下的就是利用Gson和RxJava进行数据的解析和转换最终生成符合我们需要的数据。
到这里我们开头访问妹子福利代码的执行流程基本搞清楚了,总体而言Retrofit源码比较简单而且设计的非常好,建议大家都去认真阅读下。

最后总结下阅读源码的三点感受:
1. 不要只看分析文章,自己分析源码很重要
2. 结合代码,从一个点开始顺藤摸瓜,总会找到让你高潮的代码与逻辑
3. 断点调试很重要!断点调试很重要!断点调试很重要!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值