美文网首页
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