美文网首页
Retrofit源码分析

Retrofit源码分析

作者: 一线游骑兵 | 来源:发表于2019-01-04 23:17 被阅读3次

目的:分析使用Retorfit发起一个网络请求的总过程。

首先看一下项目中Retrofit的构建过程:

    public static Api getNetService() {
        if (commmonApi == null) {
            Gson gson = new GsonBuilder().setLenient().create();
            commmonApi = new Retrofit.Builder().client(OkHttpClientUtils.getOkHttpClient())
                    .baseUrl(HttpConfig.BASE_URL)  //请求服务器地址
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build().create(Api.class);
        }
        return commmonApi;
    }

使用的时候,声明一个借口类用来存放每个请求的信息:
Api.class

public interface Api {
    @FormUrlEncoded
    @POST("v1/search.do")  //具体接口地址
    Observable<BaseBean<SearchResultBean>> search(@FieldMap Map<String, String> paramMap);
}

发起搜索请求示例(真实项目肯定会进行封装,此处只是示例):

    ParamMap paramMap = new ParamMap();
    paramMap.put("pageNo", pageNo + "");
    paramMap.put("pageSize", pageSize + "");
    NetService.getNetService().search(paramMap)
         .delay(delayMillis, TimeUnit.MILLISECONDS)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribeOn(Schedulers.io())
        .subscribe(new Observer<BaseBean<T>>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {              
            }

            @Override
            public void onNext(@NonNull BaseBean<T> tBaseBean) {             
            }

            @Override
            public void onError(@NonNull Throwable e) {            
            }

            @Override
            public void onComplete() {               
            }
        });

首先第一个问题:NetService.getNetService().search(paramMap)是如何进行调用的,明明声明的只是一个接口!
只能从Retrofit的构建过程入手了:

new Retrofit.Builder().client(OkHttpClientUtils.getOkHttpClient())
                    .baseUrl(HttpConfig.BASE_URL)  //请求服务器地址
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build().create(Api.class);

前边都是通过Retrofit的构建者来配置参数,create才是真正创建并返回Api对象的方法:

  public <T> T create(final Class<T> service) {

    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
          //1.获取该方法的所有必要信息
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
          //2. 封装请求信息与参数
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //3.发起调用
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

核心代码如上,恍然大悟,原来是通过动态代理来进行反射调用的。其中的method就是发起的请求方法search,args就是被@FieldMap注解修饰的Map参数。
简单的三步调用,下文主要就是围绕着1,3注释代码语句展开。
在展开之前,首先要明确几个大块的作用【由于篇幅时间有限,该文只分析主干流程,具体细节不再展开,沉迷于细节也容易影响进度】

  1. CallAdapter:适配器,通过.addCallAdapterFactory(RxJava2CallAdapterFactory.create())传入,主要作用就是兼容Android、Rxjava、Guava和java8这4个平台或类库,默认返回的就是Call,使用的应该就是转换器模式。此处传入的是RxJava2CallAdapter,它后续的作用就是讲OkHttp返回的Call<T> 转换为 Observable<T>。该适配器最终会传递给ServiceMethod类中的callAdapter变量。
  2. Converter:转换器,通过.addConverterFactory(GsonConverterFactory.create(new Gson()))传入,作用就是对OkHttp请求的结果Response的body进行解析,根据不同的返回内容使用不同的转换器,此处返回的内容是json格式,所以通过Gson来转换为对应的Bean实体类。该转换器最终会传递给ServiceMethod中的responseConverter变量。
  3. responseType:返回类型,此处为BaseBean<SearchResultBean>,也是ServiceMethod中的一个变量。

上边的3个对象都是ServiceMethod中的成员变量。知道了这3个变量的作用,我们就开始分析第一行注释的代码:

        //1.获取该方法的所有必要信息
  ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);

  ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        //如果没有命中缓存,则通过builder创建一个
        result = new ServiceMethod.Builder<>(this, method).build();    
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

build()方法:

  public ServiceMethod build() {
      //通过方法返回参数类型获取对应的适配器,此处为RxJava2CallAdapter
      callAdapter = createCallAdapter();    

      //获取返回类型
      responseType = callAdapter.responseType();
      //获取Response的解析转换器,此处为GsonResponseBodyConverter
      responseConverter = createResponseConverter();

      //解析方法注解获取信息,如POST/GET,请求地址,isMultipart等
      for (Annotation annotation : methodAnnotations) {  
        parseMethodAnnotation(annotation);  
      }
      //处理参数
      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);
    }

方法说明:

  1. 生成callAdapter,根据返回类型寻找最适合的适配器。
  2. 获取返回类型responseType,在接收到结果时,需要借助转换器将字符流转换成对应的Bean。
  3. 生成结果转换器,在收到Response时,对内容进行转换。
  4. 其他:获取该请求的relativeUrl,因为在创建Retrofit的时候传入了BASE_URL。等等。

ok,第一行代码大概解释完毕,看第二行代码:

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);


/**OKHttpCall类**/
  OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }

将请求接口信息以及参数封装到OKHttpCall中,OKHttpCall是真正的请求发起者。第二行不做过多解释,看第三行:

            //3.发起调用
            return serviceMethod.adapt(okHttpCall);

进入ServiceMethod.adapt方法:

  T adapt(Call<R> call) {
    return callAdapter.adapt(call);
  }

最终调用的是 callAdapter.adapt(call);,上边分析过callAdapter本质是RxJava2CallAdapter,因此最终的实现是RxJava2CallAdapter中的adapt方法:

  @Override public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }
    ...
    return observable;
  }

其他情况不再分析,根据调试(接口返回的内容也都存放在body中),结果返回的就是new BodyObservable<>(new CallExecuteObservable<>(call));,典型的代理模式【or 包装者模式?】。
分析到这儿,起码明白了一件事情:我们在Api接口类中定义的接口的返回类型就是BodyObservable,该类源码如下:

final class BodyObservable<T> extends Observable<T> {
  private final Observable<Response<T>> upstream;

  BodyObservable(Observable<Response<T>> upstream) {
    this.upstream = upstream;
  }
  //外部发起订阅时,最终对走该方法
  @Override protected void subscribeActual(Observer<? super T> observer) {
    upstream.subscribe(new BodyObserver<T>(observer));
  }

  private static class BodyObserver<R> implements Observer<Response<R>> {
    private final Observer<? super R> observer;
    private boolean terminated;
    //项目中自己定义的observer,对其进行了代理
    BodyObserver(Observer<? super R> observer) {
      this.observer = observer;
    }

    @Override public void onSubscribe(Disposable disposable) {
      observer.onSubscribe(disposable);
    }

    @Override public void onNext(Response<R> response) {
      if (response.isSuccessful()) {
        observer.onNext(response.body());
      } else {
        terminated = true;
        Throwable t = new HttpException(response);
        try {
          observer.onError(t);
        } catch (Throwable inner) {
          Exceptions.throwIfFatal(inner);
          RxJavaPlugins.onError(new CompositeException(t, inner));
        }
      }
    }

    @Override public void onComplete() {
      if (!terminated) {
        observer.onComplete();
      }
    }

    @Override public void onError(Throwable throwable) {
      if (!terminated) {
        observer.onError(throwable);
      } else {
        // This should never happen! onNext handles and forwards errors automatically.
        Throwable broken = new AssertionError(
            "This should never happen! Report as a bug with the full stacktrace.");
        //noinspection UnnecessaryInitCause Two-arg AssertionError constructor is 1.7+ only.
        broken.initCause(throwable);
        RxJavaPlugins.onError(broken);
      }
    }
  }
}

该类中还有一个内部类:BodyObserver,构造函数中传入了我们外部自己创建的Observer对象,从而对齐进行了代理【代理模式】,那么最终我们subscribe的时候,最终会走到还类中的 subscribeActual方法。

upstream.subscribe(new BodyObserver<T>(observer));

可以看到,最终的生产者是upstream,该生产者会将事件发送给BodyObserveronSubscribe/onNext/onComplete/onError中。而这个upstream就是CallExecuteObservable,因此最终的执行是在CallExecuteObservable的订阅方法中:

  @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    Call<T> call = originalCall.clone();
    CallDisposable disposable = new CallDisposable(call);
    observer.onSubscribe(disposable);     //onSubscribe回调给BodyObserver的onSubscribe

    boolean terminated = false;
    try {
      Response<T> response = call.execute();    //####执行真正的网络请求!
      if (!disposable.isDisposed()) {
        observer.onNext(response);   onNext
      }
      if (!disposable.isDisposed()) {
        terminated = true;
        observer.onComplete();      //onComplete回调给BodyObserver的onComplete
      }
    } catch (Throwable t) {
 
      if (terminated) {
        RxJavaPlugins.onError(t);
      } else if (!disposable.isDisposed()) {
        try {
          observer.onError(t);      //onError回调给BodyObserver的onError
        } catch (Throwable inner) {
        }
      }
    }
  }

**终于拨开云雾见天明了,终于发现了请求的真正发起处。还记得吗?此处的call就是第二部封装好的OKHttpCall,因此真正的执行者最终是在OKHttpCallexecute()方法:

  @Override public Response<T> execute() throws IOException {
    okhttp3.Call call;
      call = rawCall;
    if (call == null) {
        try {
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException | Error e) {
          throw e;
        }
      }
    return parseResponse(call.execute());
  }

再坚持一下,看一下这个rawCall是如何创建的:

  /** 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);

    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

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

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

最终是把一系列参数传递给callFactory创建的,而这个callFactory就是我们构建Retrofit的时候传入的

new Retrofit.Builder().client(OkHttpClientUtils.getOkHttpClient())
                    .baseUrl(HttpConfig.BASE_URL)
                    .addConverterFactory(ScalarsConverterFactory.create())
                     ...

因此这个callFactory实质就是一个OkHttpClient,因此这个rawCall最终的创建是在OKHttpClient的newCall()方法中:

  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

对于okhttp库中的东西不再分析,此处只需要明白,最终是通过client()传入的一个客户端来真正处理一个请求,这个客户端可以是okhttp,也可以是其他的请求库,实质上Retrofit只是一个解耦的模式套路或者代理,使用方便简洁,并没有真正发起请求的功能。
真正的call已经找到,接下来只需要解析call.execute()一下返回的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();
    //...处理异常code
    //对原始的body进行加工
    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      //通过responseConverter.convert(body);即GsonResponseBodyConverter进行body与实体的转换
      T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);    //返回包装的Response给BodyObserver
    } catch (RuntimeException e) {
      throw e;
    }
  }

CallExecuteObservable类中的subscribeActual方法中拿到Response后,随机会将事件发送给BodyObserver,而BodyObserver会再次转发给我们自己创建的Observer。至此,一个完成的网络请求调用就分析完毕。

总结:
1. 构建Retrofit:
  • 通过client(*)传入真正发起请求的网络客户端,此处为okhttp
  • 通过.baseUrl(HttpConfig.BASE_URL)传入服务器地址。
  • 通过.addConverterFactory(GsonConverterFactory.create(gson))传入结果转换器,此处转换为json。
  • 通过 .addCallAdapterFactory(RxJava2CallAdapterFactory.create())传入类库适配器,此处为RxJava。
  • 通过.create(Api.class);传入接口定义类。
2. 在.create(Api.class)方法中,动态代理该类中的所有请求方法。
3. 代理拦截到请求做以下处理:
  • 根据注解获取请求方法的信息,如POST/GET,接口地址,返回类型,请求参数Map等信息。
  • 根据返回参数来确定转换器,此处转换为Observable<T>
  • 将所有请求信息封装到OkHttpCall类中
4. 通过RxJava2CallAdapterFactory转换器将Call封装成包装了CallEnqueueObservable的BodyObservable【都是Observable的子类】,并代理(or 包装)项目中传入的ObserverBodyObserver,然后在项目subscribe发起订阅的时候,通过被代理对象CallEnqueueObservable发起真正的订阅。
5. 在CallEnqueueObservable类中的订阅方法中,通过使用okhttp生成的call来发起真正的请求,在得到Response响应后,根据传入的转换器(GsonConverterFactory)转换为对应的实体类型(BaseBean)并回调给BodyObserver中的onNext(BaseBean),当然还有onCompleteonError回调。在BodyObserver收到回调时会再回调给我们项目中创建的Observer。至此,一个完整的请求完毕。
完。

相关文章

网友评论

      本文标题:Retrofit源码分析

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