美文网首页android 进阶
Retrofit 源码分析

Retrofit 源码分析

作者: 庞哈哈哈12138 | 来源:发表于2017-06-16 17:47 被阅读9次

    我在半年前才开始接触 Retrofit,在那个时候这个框架已经很火了。作为入门学习,简单梳理了一下写成一篇文章。有不对的地方,望指正。
    好,开始进攻。
    Retrofit 的创建
    使用 Retrofit 的时候,首先通过建造者模式来创建 Retrofit 对象,创建姿势是这样的:

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

    先看到 Builder 的构造方法,

    public Builder() {
      this(Platform.get());
    }
    
    private static final Platform PLATFORM = findPlatform();
    
    static Platform get() {
      return PLATFORM;
    }
    

    获取运行的平台,至于怎么获取?通过 Class.forName() 的方式来查找。如下:

    private static Platform findPlatform() {
      try {
        Class.forName("android.os.Build");
        if (Build.VERSION.SDK_INT != 0) {
          return new Android();
        }
      } catch (ClassNotFoundException ignored) {
      }
      try {
        Class.forName("java.util.Optional");
        return new Java8();
      } catch (ClassNotFoundException ignored) {
      }
      try {
        Class.forName("org.robovm.apple.foundation.NSObject");
        return new IOS();
      } catch (ClassNotFoundException ignored) {
      }
      return new Platform();
    }
    

    有三种,Android,Java8,iOS。至此,我们知道了 Retrofit 有一个 Platform 对象叫 android
    继续看到 build 方法。

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
    
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
    
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
    
      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
    

    可以看到 baseUrl 是一定要设置的。不然抛出异常就 GG 了。因为是第一次调用 build 方法来创建 Retrofit,很多参数都是还没有配置的。
    比如:

    if (callbackExecutor == null) {
      callbackExecutor = platform.defaultCallbackExecutor();
    }
    

    刚才已经知道了 Retrofit 有一个 Platform 对象叫 Android。所以这时我们跟进到 Android 的defaultCallbackExecutor方法。如下:

    static class Android extends Platform {
      @Override public Executor defaultCallbackExecutor() {
        return new MainThreadExecutor();
      }
    
      @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
        return new ExecutorCallAdapterFactory(callbackExecutor);
      }
    
      static class MainThreadExecutor implements Executor {
        private final Handler handler = new Handler(Looper.getMainLooper());
    
        @Override public void execute(Runnable r) {
          handler.post(r);
        }
      }
    }
    

    返回了一个 MainThreadExecutor,好了,从这里我们可以得出结论,那个 callbackExecutor 就是 MainThreadExecutor,当 callbackExecutor 调用 execute 方法时,就切换到了主线程。
    继续前进,来到

    adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
    

    这是一行很神奇的代码,首先,还是调用 Platform 的方法,将刚才得到的 callbackExecutor,也就是 MainThreadExecutor,又传进了自己的defaultCallAdapterFactory 方法,这个 defaultCallAdapterFactory 内部生成了一个 ExecutorCallAdapterFactory。
    好了,上面那一行神奇的代码,其实就是将一个 ExecutorCallAdapterFactory 添加进一个集合。 我们在创建 Retrofit 的时候,调用了 addCallAdapterFactory 配置了RxJavaCallAdapterFactory。这个 CallAdapter.Factory 也添加进了刚才的集合

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

    ExecutorCallAdapterFactory 和 RxJavaCallAdapterFactory 都是继承自 CallAdapter.Factory 的。我们猜,这两个 CallAdapter.Factory 是干什么用的?是用来将结果适配的。
    接着继续,同理,

    List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    

    这是将配置的 GsonConverterFactory 添加进来一个集合。
    到这里,创建Retrofit对象完毕。总结一下,其实就是配置参数嘛。
    创建接口对象
    创建了 Retrofit 对象,调用 create 方法来创建接口对象,比如:

    IUserBiz userBiz = retrofit.create(IUserBiz.class);
    

    使用了动态代理来创建接口对象,跟进 create 揭开谜底。

    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);
            }
          });
    }
    

    通过 create 方法拿到了接口对象后,接口对象肯定需要调用接口方法吧,
    调用接口方法

    Call<List<User>> call = userBiz.getUsers();
    

    当调用接口方法的时候,就会调用到 InvocationHandler 的 invoke 方法,执行其内部的逻辑。
    我们看到,调用了接口方法返回的了一个 Call 对象,如果设置了RxJavaCallAdapterFactory,返回的就是一个 Observable 对象。
    那么结论我们已经知道了,invoke 方法内部的逻辑就变的很神秘,他到底是怎么返回一个 Call 对象或 Observable 对象的呢?
    看到 loadServiceMethod 方法,这里传进了一个 Method 对象,即我们调用的接口方法。(方法也是对象,是 Method 类的对象)

    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;
    }
    

    从 Cache 这个字眼可以猜测是先从缓存中查找,一个 method 对象对应一个 ServiceMethod 对象。 如果缓存不存在,使用建造者模式来创建 ServiceMethod 对象,之后在添加进缓存。好,看下怎么创建 ServiceMethod 对象。同样先是看 Builder 的构造方法,

    public Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }
    

    这里做了一些初始化工作,取出了接口方法的注解、参数类型、参数的注解。
    好的,回到build方法。

    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);
    }
    

    首先 createCallAdapter() 获取的是创建 Retrofit 时设置的 CallAdapterFactory,一开始我们设置了 RxJavaCallAdapterFactory。同理 createResponseConverter() 方法获取的是 GsonConverterFactory。
    接着,就是从接口方法注解数组中取出注解,并调用 parseMethodAnnotation 解析。如果没有设置请求方法的注解等,比如@GET、@POST,会抛出异常的。最后是解析方法参数的注解。创建了 ServiceMethod。

    ServiceMethod(Builder<T> builder) {
      this.callFactory = builder.retrofit.callFactory();
      this.callAdapter = builder.callAdapter;
      this.baseUrl = builder.retrofit.baseUrl();
      this.responseConverter = builder.responseConverter;
      this.httpMethod = builder.httpMethod;
      this.relativeUrl = builder.relativeUrl;
      this.headers = builder.headers;
      this.contentType = builder.contentType;
      this.hasBody = builder.hasBody;
      this.isFormEncoded = builder.isFormEncoded;
      this.isMultipart = builder.isMultipart;
      this.parameterHandlers = builder.parameterHandlers;
    }
    

    将参数全部塞给 ServiceMethod。
    有了 ServiceMethod 后,回到 invoke 方法,会创建 OkHttpCall,

    OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
      this.serviceMethod = serviceMethod;
      this.args = args;
    }
    

    只是进行了一些赋值。
    最后,关键来了

    return serviceMethod.callAdapter.adapt(okHttpCall);
    

    刚才我们提到,在 serviceMethod 的创建过程,会拿到创建 Retrofit 时设置的 callAdapter,所以这里的 serviceMethod.callAdapter,就是RxJavaCallAdapterFactory,那么直接看到 RxJavaCallAdapterFactory 的 adapt 方法即可。

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

    返回了一个 observable,之后就可以把复杂逻辑都能穿成一条线了。
    如果,我并不想使用 RxJava,即没有设置 RxJavaCallAdapterFactory 呢? 这时 serviceMethod.callAdapter 又是什么?当然是 ExecutorCallAdapterFactory。如下:

    @Override public <R> Call<R> adapt(Call<R> call) {
      return new ExecutorCallbackCall<>(callbackExecutor, call);
    }
    

    创建了 ExecutorCallbackCall,并将 MainThreadExecutor 和 OkHttpCall 传进。ExecutorCallbackCall 当然是继承自Call的。也就是返回给我们的Call对象。
    那么现在看到 ExecutorCallbackCall 就好了。注意,这里传进的 call 是 OkHttpCall。好,继续前进。看到构造方法

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
    

    喔,OkHttpCall 变成了 delegate。到这里就好了。
    执行Call
    之后,如果我们拿到的是Call对象,使用姿势是这样的: 异步:

    call.enqueue(new Callback<List<User>>() {
        @Override
        public void onResponse(Call<List<User>> call, Response<List<User>> response) {
    
        }
    
        @Override
        public void onFailure(Call<List<User>> call, Throwable t) {
    
        }
    });
    

    同步:

    call.execute();
    

    ok,那我们现在回来看,这个 call 调用 enqueue或execute,实际上调用的是ExecutorCallbackCall 的 enqueue 或 execute 方法。我们分析 enqueue 方法即可。如下:

    @Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");
    
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on 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(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }
    

    可以看到,把请求的任务转交给了 delegate,也就是 OkHttpCall。 而 callbackExecutor,也就是 MainThreadExecutor,调用了 execute 方法,在这里完成了线程的切换,具体如下:

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());
    
      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
    

    ok,那么现在只需要关注到 OkHttpCall 即可。同样看到入队方法,如下:

    @Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");
    
      okhttp3.Call call;
      Throwable failure;
    
      synchronized (this) {
        if (executed) throw new IllegalStateException("Already executed.");
        executed = true;
    
        call = rawCall;
        failure = creationFailure;
        if (call == null && failure == null) {
          try {
            call = rawCall = createRawCall();
          } catch (Throwable t) {
            failure = creationFailure = t;
          }
        }
      }
    
      if (failure != null) {
        callback.onFailure(this, failure);
        return;
      }
    
      if (canceled) {
        call.cancel();
      }
    
      call.enqueue(new okhttp3.Callback() {
        @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
            throws IOException {
          Response<T> response;
          try {
            response = parseResponse(rawResponse);
          } catch (Throwable e) {
            callFailure(e);
            return;
          }
          callSuccess(response);
        }
    
        @Override public void onFailure(okhttp3.Call call, IOException e) {
          try {
            callback.onFailure(OkHttpCall.this, e);
          } catch (Throwable t) {
            t.printStackTrace();
          }
        }
    
        private void callFailure(Throwable e) {
          try {
            callback.onFailure(OkHttpCall.this, e);
          } catch (Throwable t) {
            t.printStackTrace();
          }
        }
    
        private void callSuccess(Response<T> response) {
          try {
            callback.onResponse(OkHttpCall.this, response);
          } catch (Throwable t) {
            t.printStackTrace();
          }
        }
      });
    }
    

    可以看到,OkHttpCall只是包装了Okhttp,咦,其实这个从名字也能猜出来的。底层实现还是Okhttp。createRawCall 方法会调用 serviceMethod.toRequest 生成一个 Request ,这时那些通过解析注解获取的httpMethod终于派上用场了,toRequest 大概是这样的,可以脑补一下:

     RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
            contentType, hasBody, isFormEncoded, isMultipart);
    

    你可能会疑惑,GsonConverterFactory 为什么没有用到?其实是有的,需要继续跟进一下,当 Okhttp 请求成功,会调用 parseResponse 方法来解析结果,看到这个方法没?看到了 在 parseResponse 方法中, serviceMethod 会调用 toResponse 方法,对结果进行转换,使用的是 Gson。
    好了,相信同步调用也可以分析了。当然,如果是使用 observable,和 call 对象调用是同理的。
    全文完毕!

    相关文章

      网友评论

        本文标题:Retrofit 源码分析

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