美文网首页
Retrofit源码解析

Retrofit源码解析

作者: 天上飘的是浮云 | 来源:发表于2021-11-29 17:44 被阅读0次

    前边OkHttp的源码顺藤摸瓜,摸了个遍。但是我们用的比较多的还是Retrofit,都是square的佳作,它是在OKHttp上进行了封装,对开发者变得更加友好。本文基于retrofit: 2.9.0开撸。

    一、Retrofit在OKHttp上新增了什么魔法

    • 使用动态代理模式使用接口和注解方式定义请求方法,对应用层友好,使用容易理解和方便
    • 它可以和RxJava配合使用,超级解耦
    • 它可以定制很多解析转换器,来将接口返回的数据封装为我们的JavaBean对象
    • 在请求回来后,它会自动切换为主线程,无需额外在应用内部进行线程的切换

    二、Retrofit的基本用法

    Retrofit用法其实也不用多讲,很简单:

      1. 首先,新建个请求接口类
    interface TestRetrofitService {
    
        @GET("test")
        fun getTestParms(): Call<ResponseBody>
    }
    
      1. 再构建一个全局的Retrofit实例,它也是基于建造者模式
    var retrofit: Retrofit = Retrofit.Builder().baseUrl("http://www.baidu.com").build()
    
      1. 然后使用Retrofit实例动态生成一个请求接口的代理对象
    var testRetrofitService: TestRetrofitService = retrofit.create(TestRetrofitService::class.java)
    

    *4. 使用代理对象调用请求接口方法,生成一个Call对象

    val testCall: Call = testRetrofitService.getBaiduParms();
    
      1. 调用Call的enqueue方法,发起异步请求,execute方法则是同步请求
         testCall.enqueue(object: retrofit2.Callback<ResponseBody>{
                override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
                    TODO("Not yet implemented")
                }
    
                override fun onResponse(call: retrofit2.Call<ResponseBody>, response: retrofit2.Response<ResponseBody>) {
                    TODO("Not yet implemented")
                }
    
            })
    

    三、Retrofit是如何通过建造者模式实例化的?

    Retrofit.Builder().baseUrl("http://www.baidu.com").build()
    
      1. Retrofit有个Builder内部类,它有两个构造方法,它会传入平台类,并通过jvm虚拟机的名字判断是Android平台还是Java平台。
       Builder(Platform platform) {
          this.platform = platform;
        }
    
        public Builder() {
          this(Platform.get());
        }
    
      private static Platform findPlatform() {
        return "Dalvik".equals(System.getProperty("java.vm.name"))
            ? new Android() //
            : new Platform(true);
      }
    
      1. 然后通过Retrofit.Builder实例可以传入很多配置参数,这和OKHttp一致,最后通过build()方法,实例化Retrofit
        public Retrofit build() {
          if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
          }
    
          ...
    
          return new Retrofit(
              callFactory,
              baseUrl,
              unmodifiableList(converterFactories),
              unmodifiableList(callAdapterFactories),
              callbackExecutor,
              validateEagerly);
        }
    

    四、Retrofit是如何通过动态代理实例化请求接口类的代理对象?

    //请求接口类
    interface TestRetrofitService {
    
        @GET("meinv")
        fun getBaiduParms(): Call<ResponseBody>
    }
    
    //通过动态代理实例化一个代理对象
    var testRetrofitService = retrofit.create(TestRetrofitService::class.java)
    
    

    跟踪Retrofit.create()方法,映入眼前的就是妥妥的动态代理模式了,Proxy.newProxyInstance()。通过动态代理返回了一个TestRetrofitService接口类的代理对象

      public <T> T create(final Class<T> service) {
        return (T)
            Proxy.newProxyInstance(
                service.getClassLoader(),
                new Class<?>[] {service},
                new InvocationHandler() {
                  ...
                  @Override
                  public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                      throws Throwable {
                    ...
    158行                return platform.isDefaultMethod(method)
                        ? platform.invokeDefaultMethod(method, service, proxy, args)
                        : loadServiceMethod(method).invoke(args);
                  }
                });
      }
    

    五、Retrofit生成的动态代理对象调用请求方法后,如何返回的Call对象的?

    val testCall: Call = testRetrofitService.getBaiduParms();

      1. 我们可以看到上面动态代理158行,这里又是Android和java平台的判断,这里直接可以看到
    loadServiceMethod(method).invoke(args)
    
      1. 在loadServiceMethod()方法中,它将对传入的Method的注解进行解析保存为一个ServiceMethod对象并缓存起来。
      ServiceMethod<?> loadServiceMethod(Method method) {
        //1. 首先冲缓存中获取,获取到了就返回
        ServiceMethod<?> result = serviceMethodCache.get(method);
        if (result != null) return result;
    
        //2. 为了线程安全问题,加了锁
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            //3. 开始解析Annotations
            result = ServiceMethod.parseAnnotations(this, method);
            //4. 将解析好的serviceMethod缓存起来
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }
    
      1. ServiceMethod是一个抽象类,HttpServiceMethod为其子类
    static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    26行    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    
        Type returnType = method.getGenericReturnType();
       ...
    
        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
      }
    
      1. 如上26行,它通过RequestFactory类的parseAnnotations()方法解析请求接口类的方法上和参数的注解。

    在RequestFactory里实际也是通过建造者模式,返回了RequestFactory实例

     static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
        return new Builder(retrofit, method).build();
      }
    

    通过查看Builder内部类中的build方法,发现了很多解析Annotation注解的方法。

        RequestFactory build() {
          for (Annotation annotation : methodAnnotations) {
    181行        parseMethodAnnotation(annotation);
          }
          ...
    
          int parameterCount = parameterAnnotationsArray.length;
          parameterHandlers = new ParameterHandler<?>[parameterCount];
          for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
    205行        parameterHandlers[p] =
                parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
          }
    
         ...
          return new RequestFactory(this);
        }
    

    181行解析的是方法上的注解:这里大家看着都懂,无非就是解析方法上的一个@GET、@POST等注解,并获取值,并保存在成员变量中

    private void parseMethodAnnotation(Annotation annotation) {
          if (annotation instanceof DELETE) {
            parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
          } else if (annotation instanceof GET) {
            parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
          }
      ...
    }
    

    205行解析的是方法上的注解:这里就是将方法里的每个参数单独保存为一个ParameterHandler实例

        private @Nullable ParameterHandler<?> parseParameter(
            int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
          ParameterHandler<?> result = null;
          if (annotations != null) {
            for (Annotation annotation : annotations) {
              ParameterHandler<?> annotationAction =
                  parseParameterAnnotation(p, parameterType, annotations, annotation);
       ...
    }
    

    后续的如何解析,大家可以深入代码中看看,这里就不一一贴代码了。比较简单,就是注解的解析取值,存值过程。

      1. 前边的ServiceMethod.parseAnnotations()方法最终返回了一个HttpServiceMethod实例,而HttpserviceMethod是ServiceMethod的子类
     static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
        ...
        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
      }
    
      1. 回到第2点,动态代理最终返回的是loadServiceMethod(method).invoke(args),而loadServiceMethod(method)返回的是一个HttpServiceMethod的实例,我们看看它的invoke()方法,这里就实例化了一个OKHttpCall对象,而它就是Call的子类。这里其实它还被另外一个ExecutorCallbackCall包装了一层(adapt(call, args)方法包装)。这里先不讲。
      final @Nullable ReturnT invoke(Object[] args) {
        Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
        return adapt(call, args);
      }
    

    六、Retrofit如何通过Call实例对象发起请求的?

       testCall.enqueue(object: retrofit2.Callback<ResponseBody>{
            override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
                TODO("Not yet implemented")
            }
    
            override fun onResponse(call: retrofit2.Call<ResponseBody>, response: retrofit2.Response<ResponseBody>) {
                TODO("Not yet implemented")
            }
    
        })
    

    前面知道了其实真正执行请求的Call就是OKHttpCall,我们跟踪enqueue()方法进去看看。

      1. 调用OKHttpCall.enqueue()方法
      @Override
      public void enqueue(final Callback<T> callback) {
        okhttp3.Call call;
        synchronized (this) {
          call = rawCall;
          if (call == null && failure == null) {
            try {
    130行          call = rawCall = createRawCall();
            } catch (Throwable t) {
            }
          }
        }
    
    147行    call.enqueue(
            new okhttp3.Callback() {
              @Override
              public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
                  callback.onResponse(OkHttpCall.this, response);
              }
    
              @Override
              public void onFailure(okhttp3.Call call, IOException e) {
                callback.onFailure(OkHttpCall.this, e);
              }
            });
      }
    
      1. 它在130行调用了createRawCall()方法,它调用了callFactory.newCall方法创建出okHttp3.Call对象
    private okhttp3.Call createRawCall() throws IOException {
        okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
       ...
        return call;
      }
    
      1. 这里的callFactory实际上就是OKHttpClient,这在之前建造者模式创建Retrofit实例的build()方法中可以看到,而OkHttpClient.newCall()方法实际上就是返回了一个RealCall对象
    public Retrofit build(){
          okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) {
            callFactory = new OkHttpClient();
          }
    ...
    }
    
      @Override public Call newCall(Request request) {
        return RealCall.newRealCall(this, request, false /* for web socket */);
      }
    
      1. requestFactory.create(args)方法呢,就是返回了一个Request请求对象。
      okhttp3.Request create(Object[] args) throws IOException {
        @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
        ...
    
        RequestBuilder requestBuilder =
            new RequestBuilder(
                httpMethod,
                baseUrl,
                relativeUrl,
                headers,
                contentType,
                hasBody,
                isFormEncoded,
                isMultipart);
    
        ...
    
        return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
      }
    
      1. 回到1中的147行,call.enqueue()实际就是使用OKHttp的ReallCall对象开始将请求进行分发,或加入执行队列或加入等待队列。这里和之前写的《OKHttp源码解析》请求流程一致了。然后在回调接口。

    七、Retrofit如何在返回response时,切换到主线程可以直接渲染UI的?

    这里讲起来有点绕:

      1. 先回到Retrofit的创建来,在Build.buid()方法中,它会为Retrofit默认添加平台默认的CallAdapter适配器工厂,如android平台就添加Android类中的callbackExecutor(PS: Android是platform的子类,实现了defaultCallbackExecutor方法)
    public Retrofit build() {
    ...
     Executor callbackExecutor = this.callbackExecutor;
          if (callbackExecutor == null) {
    631行        callbackExecutor = platform.defaultCallbackExecutor();
          }
          638行 callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
    ...
    }
    
      1. 631行获取了平台默认的回调执行器,这里就是线程切换的地方,而Android是Platform内部子类。它返回了一个MainThreadExecutor()对象,而它实际上就是通过new Handler(Looper.getMainLooper()),Handler来实现切回主线程。
      static final class Android extends Platform {
    
    
        @Override
        public Executor defaultCallbackExecutor() {
          return new MainThreadExecutor();
        }
    
        static final class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
    
          @Override
          public void execute(Runnable r) {
            handler.post(r);
          }
        }
      }
    

    八. 实际上这里已经知道Retrofit怎么切换到主线程了,那么它在哪里调用的呢?

      1. 在 上面七的638行,platform.defaultCallAdapterFactories(callbackExecutor)它通过传入callBackExecuter,返回了一个平台默认的CallAdapterFactory适配器工厂。它实际上就是返回了一个DefaultCallAdapterFactory。
      List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
          @Nullable Executor callbackExecutor) {
        DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
        return hasJava8Types
            ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
            : singletonList(executorFactory);
      }
    
      1. 前边我们说在HttpServiceMethod.invoke()返回的是一个OKHttpCall对象,其实不完全对,因为它还被CallAdapter适配器包装了一层。
      @Override
      final @Nullable ReturnT invoke(Object[] args) {
        Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
        return adapt(call, args);
      }
    
        @Override
        protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
          return callAdapter.adapt(call);
        }
    
      1. 2中所说的CallAdapter适配器就是通过DefaultCallAdapterFactory工厂的get()方法生成的。
        至于如何生成,给一个路线(是在动态代理生成代理对象,并通过代理对象调用请求方法时):
    1. ServiceMethod.parseAnnotations()
    2.HttpServiceMethod.parseAnnotations()
        CallAdapter<ResponseT, ReturnT> callAdapter =
            createCallAdapter(retrofit, method, adapterType, annotations);
    3. HttpServiceMethod.createCallAdapter()
    4. Retrofit.callAdapter()
    5. Retrofit.nextCallAdapter()
        public CallAdapter<?, ?> nextCallAdapter(
          CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
          ...
          for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
            CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
            return adapter;
         }
        }
    
      1. 看到DefaultCallAdapterFactory.get()方法,它返回了一个CallAdapter对象。
      public @Nullable CallAdapter<?, ?> get(
          Type returnType, Annotation[] annotations, Retrofit retrofit) {
        ...
     47行   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);
          }
        };
      }
    
      1. 47行:callbackExecutor实际就是1中的MainThreadExecutor,最后return CallAdapter,在CallAdapter的adapt方法中返回了一个ExecutorCallbackCall对象
    new ExecutorCallbackCall<>(executor, call)
    
      1. 这个传入的参数call就是OKHttpCall, 而ExecutorCallbackCall就是包装OKHttpCall的,它主要用来回调时做线程切换用途的。它也是call的子类。它是DefautlCallAdapterFactory内部类
     static final class ExecutorCallbackCall<T> implements Call<T> {
    
        @Override
        public void enqueue(final Callback<T> callback) {
          //1. delegate就是OKHttpCall,实际上就是OKHttpCall.enqueue()
          delegate.enqueue(
              new Callback<T>() {
                @Override
                public void onResponse(Call<T> call, final Response<T> response) {
                  //2. 请求返回后使用MainThreadExecutor对象切换线程
                  callbackExecutor.execute(
                      () -> {
                        if (delegate.isCanceled()) {
                          // 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));
                }
              });
        }
    }
    
    1. delegate就是OKHttpCall,实际上就是OKHttpCall.enqueue()
    2. 请求返回后使用MainThreadExecutor对象切换线程
                  callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
    

    九、结语

    我们通过Retrofit的主线了解清楚了,Retrofit如何通过动态代理和注解反射等机制对OKHttp进行封装。对于我们灵活使用Retrofit来开发和解决使用Retrofit中遇到的问题非常有帮助,另外也通过跟踪框架源码,对于搭建框架也有了更多的认识和理论支撑。

    相关文章

      网友评论

          本文标题:Retrofit源码解析

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