Retrofit2源码解析

来源:互联网 发布:linux磁盘阵列 编辑:程序博客网 时间:2024/05/16 04:59

  最近项目将网络框架换成Retrofit2.0.2,文中说的Retrofit都是指的Retrofit2这里要说明一下,毕竟和Retrofit1差别还是蛮大的,结合Okhttp,RxJava还是比较好用的,网上有很多前辈介绍过使用方法,本文是想研究一下Retrofit的源码。关于Retrofit的介绍可以查阅Retrofit的官方网站
  直接进入主题:(注本文是结合RxJava介绍的,最好可以了解一下RxJava不了解也没有关系,大部分的思想是一样的)
  Retrofit的基本使用
  Retrofit使用是非常简单的,在上边的官网上介绍的也非常详细。但是为了后边的分析,还是把使用的代码贴在这儿:
  一般在项目中会将需要请求网络方法写在一个接口中,如下:

 public interface GitHubService {    @GET("users/{user}/repos")    Observable<List<Repo>> listRepos(@Path("user") String user); }

  如果要使用Retrofit还需要构建Retrofit的对象:

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

  主要就是配置baseUrl,ConverterFactory,CallAdapterFactory。这里用的是Gson,和RxJava所以相应的就是GsonConverterFactoryRxJavaCallAdaperFactory这个在后边的源码分析中会用到。
  最后直接调用就可以了:
  

GitHubService service = retrofit.create(GitHubService.class);service.listRepos("octocat")              .observeOn(AndroidSchedulers.mainThread())              .subscribeOn(Schedulers.io())              .subscribe(list->{              if(list!=null){              //TODO 取得数据后逻辑处理              }             });

  可以说,代码还是非常简洁的。用起来也很容易上手。
  Retrofit工作流程
  如上面的使用中我们可以看到:
1.通过Retrofit.Builder().build()构建Retrofit实例。
2.调用Retrofit的create()方法将生成接口GitHubService的实例。
3.调用GitHubService的listRepos()方法返回Observable<List<Repo>>,这里的GitHubService实例实际上是个代理对象,这个下文再说。
  下图是我整理的Retrofit运行时主要节点的时序图,当然不是所有的过程都反映出来了。
  这里写图片描述
  看不懂没关系,一步一步来,先看看Retrofit源码的构成:
    

 
  简单的介绍一下
  1.Call(接口)–向服务器发送请求并返回响应的调用
  2.CallAdapter(接口)–Call的适配器,用来包装转换Call
  3.CallAdapter.Factory(接口)–CallAdapter的工厂,通过get方法获取对应的CallAdapter
  4.CallBack(接口)–Call的回调
  5.Converter(接口)–数据转换器,将一个对象转化另外一个对象
  6.Converter.Factory(抽象类) – 数据转换器Converter的工厂
  responseBodyConverter – 将服务器返回的数据转化ResponseBody。
  requestBodyConverter – 将GitHubService.listRepos()中的Body,Part等注解转换为RequestBody(),以便Okhttp请求的时候使用。
  stringConverter – 将Field,FieldMap 值,Header,Path,Query,和QueryMap值转化为String,以便Okhttp请求的时候使用。
  7.ServiceMethod 通过解析注解,传参,会将你的接口方法调用转化为一个 Call 对象。也就说对于每一个接口方法,他都会创建一个与之对应的 ServiceMethod
  另外retrofit还有一个http包,都是用来定义 HTTP 请求的自定义注解。如果对注解不太熟悉可以看看我的ButterKnife源码剖析 关于注解的介绍。
  
 
 

  回到上边步骤2,调用Retrofit的create()方法将生成接口GitHubService的实例:
  

GitHubService service = retrofit.create(GitHubService.class);

  将GithubService.class作为参数,传入create(),然后又返回一个GithubService实例,看起来是不是很神奇。源码如下:
  

 @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.  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 {            // 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);            }            ServiceMethod serviceMethod = loadServiceMethod(method);            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);            return serviceMethod.callAdapter.adapt(okHttpCall);          }        });  }

  这里使用了动态代理,返回了一个 Proxy 代理类,调用GithubService(在自己的项目中是XXXService接口)接口中的任何方法都会调用 proxy 里的 invoke 方法。这个方法里边最重要的就是第23,24,25行代码。
  1.构建ServiceMethod实例
  先看第23行

 ServiceMethod serviceMethod = loadServiceMethod(method);

  通过loadServiceMethod方法获取ServiceMethod实例:
  

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

  第4行首先会先尝试从serviceMethodCache(类型Map<Method, ServiceMethod>)中get,如果缓存中没有则构建一个ServiceMethod实例。接着看怎么构建ServiceMethod实例,ServiceMethod.java中源码:

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() {      callAdapter = createCallAdapter();      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?");      }      responseConverter = createResponseConverter();      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).");        }      }      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);    }

  使用Builder模式来构建serviceMethod实例,将retrofit实例,和invoke的方法作为参数来初始化。第10行通过调用createCallAdapter()创建CallAdapter实例callAdapter。

 private CallAdapter<?> createCallAdapter() {      Type returnType = method.getGenericReturnType();      if (Utils.hasUnresolvableType(returnType)) {        throw methodError(            "Method return type must not include a type variable or wildcard: %s", returnType);      }      if (returnType == void.class) {        throw methodError("Service methods cannot return void.");      }      Annotation[] annotations = method.getAnnotations();      try {        return retrofit.callAdapter(returnType, annotations);      } catch (RuntimeException e) { // Wide exception range because factories are user code.        throw methodError(e, "Unable to create call adapter for %s", returnType);      }    }

  看第11行,获取到了,接口方法中使用的注解,在我们本文中的GithubService的listRepos的注解就是@Get();第13行会通过调用Retrofit的callAdapter()方法来返回CallAdapter实例:
  Retrofit.java文件中:
  

/**   * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain   * #callAdapterFactories() factories}.   *   * @throws IllegalArgumentException if no call adapter available for {@code type}.   */  public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {    return nextCallAdapter(null, returnType, annotations);  }  /**   * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain   * #callAdapterFactories() factories} except {@code skipPast}.   *   * @throws IllegalArgumentException if no call adapter available for {@code type}.   */  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;      }    }    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());  }

  真的实现是在Retrofit.java中的nextCallAdapter()方法中实现的。上边代码第25行,adapterFactories是一个缓存CallAdapter.Factory的list,我们在构建Retrofit实例时,曾经设置过addCallAdapterFactory(RxJavaCallAdapterFactory.create()),也就意味着adapterFactories.get(i)将获得到RxJavaCallAdapterFactory,然后会执行其get()方法。
  RxJavaCallAdapterFactory.java文件中:
  

 @Override  public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {    Class<?> rawType = getRawType(returnType);    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 && !(returnType instanceof ParameterizedType)) {      String name = isSingle ? "Single" : "Observable";      throw new IllegalStateException(name + " return type must be parameterized"          + " as " + name + "<Foo> or " + name + "<? extends Foo>");    }    if (isCompletable) {      // Add Completable-converter wrapper from a separate class. This defers classloading such that      // regular Observable operation can be leveraged without relying on this unstable RxJava API.      // Note that this has to be done separately since Completable doesn't have a parametrized      // type.      return CompletableHelper.createCallAdapter(scheduler);    }    CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler);    if (isSingle) {      // Add Single-converter wrapper from a separate class. This defers classloading such that      // regular Observable operation can be leveraged without relying on this unstable RxJava API.      return SingleHelper.makeSingle(callAdapter);    }    return callAdapter;  }

  正常情况下,会执行到第27行,通过getCallAdapter方法,获得Observable泛型的CallAdapter,继续跟进去看看:
  

 private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) {    Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);    Class<?> rawObservableType = getRawType(observableType);    if (rawObservableType == Response.class) {      if (!(observableType instanceof ParameterizedType)) {        throw new IllegalStateException("Response must be parameterized"            + " as Response<Foo> or Response<? extends Foo>");      }      Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);      return new ResponseCallAdapter(responseType, scheduler);    }    if (rawObservableType == Result.class) {      if (!(observableType instanceof ParameterizedType)) {        throw new IllegalStateException("Result must be parameterized"            + " as Result<Foo> or Result<? extends Foo>");      }      Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);      return new ResultCallAdapter(responseType, scheduler);    }    return new SimpleCallAdapter(observableType, scheduler);  }

  第3行会getRawType(observableType)会返回Observable具体类型,例如本例中,

 public interface GitHubService {    @GET("users/{user}/repos")    Observable<List<Repo>> listRepos(@Path("user") String user); }

  返回值是Observable<List<Repo>> 那么getRawType(observableType)将得到List.class,这样程序将执行第22行,将返回一个SimpleCallAdapter实例,那么它就是CallAdapter的真正实现。
  回到ServiceMethod的build()方法中,继续执行第18行responseConverter = createResponseConverter();过程也和createCallAdapter差不多,也是使用工厂模式,通过get()方法获得Converter的真正实现,篇幅所限就不一步一步的跟了,本例使用的是Gson,所以Converter得实现是GsonResponseBodyConverter。之后就是解析注解,参数等,这样ServiceMethod已经构建好了。
  
  生成OkHttpCall
  回到Retrofit动态代理invoke方法中,第二步就是生成Call的实例了,目前Retrofit的默认使用的是OkhttpCall。其是OkHttp的包装类,所有OkHttp需要的参数都在该类中找到。

  adapt Call
  第三步执行serviceMethod.callAdapter.adapt(okHttpCall),通过之前的分析,serviceMethod.callAdapter真正的实现是SimpleCallAdapter,那么自然也是执行的它的adapt()方法。为了证实这个,可以debug一下就知道了。
  这里写图片描述

  RxJavaCallAdapterFactory.SimpleCallAdapter.adapt():
  

@Override public <R> Observable<R> adapt(Call<R> call) {      Observable<R> observable = Observable.create(new CallOnSubscribe<>(call))           .lift(OperatorMapResponseToBodyOrError.<R>instance());      if (scheduler != null) {        return observable.subscribeOn(scheduler);      }      return observable;    }  }

  其返回类型Observable,也就是我们需要的结果,还记得我们是怎么使用的RxJava的吗?
  

service.listRepos("octocat")              .observeOn(AndroidSchedulers.mainThread())              .subscribeOn(Schedulers.io())              .subscribe(list->{              if(list!=null){              //TODO 取得数据后逻辑处理              }             });

  看代码service.listRepos(“octocat”)应该是一个Observable,而刚刚分析的,service.listRepos(“octocat”)确实会返回一个Observable,有了这个Observable之后,我们就可以通过subscribeOn给他指定运行线程,这样像网络请求耗时操作就不会再UI线程中运行,从而达到异步的目的,然后通过observeOn()将线程切回UI线程,当Okhttp请求完数据并进行相应的convert之后,就可以在UI处理相应的逻辑。
  回到adapt方法,第2行创建Observable,而new CallOnSubscribe<>(call)生成了一个OnSubscribe()的实例,而OnSubscribe继承自Action1,其只包含一个call()方法,而这个call是在CallOnSubscribe中实现:
  

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.      Call<T> call = originalCall.clone();      // Wrap the call in a helper which handles both unsubscription and backpressure.      RequestArbiter<T> requestArbiter = new RequestArbiter<>(call, subscriber);      subscriber.add(requestArbiter);      subscriber.setProducer(requestArbiter);    }  }

  首先clone了一份Call,然后生成了RequestArbiter,他继承自AtomicBoolean,实现了Subscription, Producer接口,Producer只有一个request方法;一般实现该接口的类,都会包含一个Subscriber对象和一个待处理的数据:
  

static final class RequestArbiter<T> extends AtomicBoolean implements Subscription, Producer {    private final Call<T> call;    private final Subscriber<? super Response<T>> subscriber;    RequestArbiter(Call<T> call, Subscriber<? super Response<T>> subscriber) {      this.call = call;      this.subscriber = subscriber;    }    @Override public void request(long n) {      if (n < 0) throw new IllegalArgumentException("n < 0: " + n);      if (n == 0) return; // Nothing to do when requesting 0.      if (!compareAndSet(false, true)) return; // Request was already triggered.      try {        Response<T> response = call.execute();        if (!subscriber.isUnsubscribed()) {          subscriber.onNext(response);        }      } catch (Throwable t) {        Exceptions.throwIfFatal(t);        if (!subscriber.isUnsubscribed()) {          subscriber.onError(t);        }        return;      }      if (!subscriber.isUnsubscribed()) {        subscriber.onCompleted();      }    }    @Override public void unsubscribe() {      call.cancel();    }    @Override public boolean isUnsubscribed() {      return call.isCanceled();    }  }

  那么看看request()方法到底干了什么?第16行代码call.execute()最终将执行okhttp的execute(),为什么这里会同步请求数据呢,还记得之前我们把耗时操作切换到子线程中吗?既然已经不是在UI线程了,这里就可以使用同步获取response数据了。在获取到response后就通过执行subscriber.onNext(response);这样subscribe过Observable的subscriber都可以收到数据了。而因为我们设置过observeOn(AndroidSchedulers.mainThread()),所以当我们接受到数据的时候,已经是在UI线程中了,所以就可以做后续的逻辑处理了。
  总结:Retrofit 的代码并不是很多,其底层网络通信时交由 OkHttp 3来完成的,但是Retrofit运用了大量的设计模式,代码逻辑很清晰。没事的时候,不妨研究研究,毕竟是Jake Wharton大神的杰作。
  

1 0
原创粉丝点击