Retrofit2.3.0源码分析

43 篇文章 1 订阅

此文章只对 Retrofit构建流程 和 网络请求流程 的主干思路分析。

1.Retrofit创建

Retrofit源码我们需要从Retrofit的使用开始,Retrofit明显使用了Builder模式进行初始化创建,根据Retrofit对象创建主要有六个步骤分析,分别为Builder()、baseUrl(String baseUrl)、client()、addConverterFactory()、addCallAdapterFactory()、build()。

Retrofit mRetrofit = new Retrofit.Builder()
       .baseUrl(HOST)
       .client(new OkHttpClient())
       .addConverterFactory(FastJsonConverterFactory.create())
	   .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
       .build();

1.1 Builder()构建

Builder(Platform platform) {
  this.platform = platform;
  // Add the built-in converter factory first. This prevents overriding its behavior but also
  // ensures correct behavior when using converters that consume all types.
  converterFactories.add(new BuiltInConverters());
}

public Builder() {
  // 获取平台(有Android、Java8)
  this(Platform.get());
}

Builder(Retrofit retrofit) {
  platform = Platform.get();
  callFactory = retrofit.callFactory;
  baseUrl = retrofit.baseUrl;
  converterFactories.addAll(retrofit.converterFactories);
  adapterFactories.addAll(retrofit.adapterFactories);
  // Remove the default, platform-aware call adapter added by build().
  adapterFactories.remove(adapterFactories.size() - 1);
  callbackExecutor = retrofit.callbackExecutor;
  validateEagerly = retrofit.validateEagerly;
}

构造方法中参数Platform.get() 我们来看一下获取的是什么

private static final Platform PLATFORM = findPlatform();

static Platform get() {
  return PLATFORM;
}

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) {
  }
  return new Platform();
}

可以看到Retrofit支持多平台包括Android和Java8,它会根据不同的平台设置不同的线程池,此处记录下当前的平台标记,后面使用到再做分析。

1.2 baseUrl(String baseUrl)

/**
 * Set the API base URL.
 *
 * @see #baseUrl(HttpUrl)
 */
public Builder baseUrl(String baseUrl) {
  checkNotNull(baseUrl, "baseUrl == null");
  HttpUrl httpUrl = HttpUrl.parse(baseUrl);
  if (httpUrl == null) {
    throw new IllegalArgumentException("Illegal URL: " + baseUrl);
  }
  return baseUrl(httpUrl);
}

public Builder baseUrl(HttpUrl baseUrl) {
  checkNotNull(baseUrl, "baseUrl == null");
  List<String> pathSegments = baseUrl.pathSegments();
  if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
    throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
  }
  this.baseUrl = baseUrl;
  return this;
}

很容易理解,baseUrl(String baseUrl)是配置服务器地址,如果为空会抛出异常。

1.3 client(OkHttpClient client)

/**
 * The HTTP client used for requests.
 * <p>
 * This is a convenience method for calling {@link #callFactory}.
 */
public Builder client(OkHttpClient client) {
  return callFactory(checkNotNull(client, "client == null"));
}

/**
 * Specify a custom call factory for creating {@link Call} instances.
 * <p>
 * Note: Calling {@link #client} automatically sets this value.
 */
public Builder callFactory(okhttp3.Call.Factory factory) {
  this.callFactory = checkNotNull(factory, "factory == null");
  return this;
}

client(OkHttpClient client)方法也只是记录下传进来的OkHttpClient对象,如果不传后面使用的时候会直接new OkHttpClient()进行赋值,所以需要对OkHttpClient对象进行超时设置或者其他拦截可以传入该对象。

1.4 addConverterFactory(FastJsonConverterFactory.create())

/** Add converter factory for serialization and deserialization of objects. */
public Builder addConverterFactory(Converter.Factory factory) {
  converterFactories.add(checkNotNull(factory, "factory == null"));
  return this;
}

细心的同学已经注意到我们在Buidler()构造的时候有以下一行代码,那我们主动将一个FastJsonConverterFactory添加到converterFactories中是什么用意呢?

converterFactories.add(new BuiltInConverters())

其实Converter主要作用是将HTTP返回的数据解析成Java对象,比如我们常见的网络传输数据Xml、Json、Protobuf等,而FastJsonConverterFactory则将Json转换成我们要的Java对象,不需要我们重新去解析Json数据。

1.5 addCallAdapterFactory(RxJava2CallAdapterFactory.create())

/**
 * Add a call adapter factory for supporting service method return types other than {@link
 * Call}.
 */
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
  adapterFactories.add(checkNotNull(factory, "factory == null"));
  return this;
}

可以看到CallAdapter同样是被使用list集合维护的对象,说明是可以添加多个的,但也会有默认的一个,我看下面build()方法的源码。

1.6 build()

/**
 * Create the {@link Retrofit} instance using the configured values.
 * <p>
 * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
 * OkHttpClient} will be created and used.
 */
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);
}

build()方法的思路分析一下,baseUrl为空则抛出异常;callFactory为传入的OkHttpClient对象,如果没传就new一个直接使用;callbackExecutor为线程池执行类,根据平台platform创建线程池使用,platform.defaultCallAdapterFactory(callbackExecutor)意思就是默认添加了一个CallAdapter,如果有平台线程池创建ExecutorCallAdapterFactory。callAdapter其实也是运用了适配器模式,是网络请求器Call的适配器,而Retrofit中Call就是指OkHttp,那么CallAdapter就是用来将OkHttp适配给不同平台的,Retrofit主要提供了以下四种CallAdapter:

  1. ExecutorCallAdapterFactory(默认)

  2. GuavaCallAdapterFactory

  3. Java8CallAdapterFactory

  4. RxJavaCallAdapterFactory

1.7 Builder模式流程图

综上使用Builder模式创建的Retrofit实例大致思路分析完毕,Retrofit负责接收我们配置的功能然后进行对象的初始化,这个就是Builder模式屏蔽掉创建对象的复杂过程的好处,下面梳理下流程图:

2.网络请求分析

ApiService api = retrofit.create(ApiService.java);
ApiResponse response = api.request(String param);

上面为最简单的网络请求创建,具体RxJava这里不做详细说明,主要分析一下create()方法里面做的处理,下面我们先来看看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, @Nullable 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<Object, Object> serviceMethod =
              (ServiceMethod<Object, Object>) loadServiceMethod(method);
          OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.callAdapter.adapt(okHttpCall);
        }
      });
}

我们主要看一下Proxy.newProxyInstance()这个方法,该方法三个参数,第一个是service类的类加载器,第二个service类,第三个回调接口InvocationHandler。其实就是通过动态代理生成网络请求的代理类,代理类生成后调用请求时就会被代理类拦截下来直接进入InvocationHandler的invoke方法。下面我们了解该方法:

2.1 invoke回调

该回调方法有三个参数,第一个代理类对象,第二个为被调用的方法(上面api.request(String param)中的request),第三个为参数(上面api.request(String param)中的param)。主要做了三步操作,第一步:收到被调用方法和传递的参数后,调用loadServiceMethod方法来生成一个ServiceMethod对象,这里一个ServiceMethod对象对应我们Service中的一个方法,相当于做了一层封装;第二步:创建OkHttpCall对象;第三步:CallAdapter使用。接下来重点看一下loadServiceMethod方法。

2.1.1 loadServiceMethod

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

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

它调用了ServiceMethod类,ServiceMethod类也是使用了Builder构建模式,我们看一下ServiceMethod的Builder方法。

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

分析下主要思路:

  1. 对注解的合法性进行检验,例如HTTP请求方法是GET还是POST,都不是则抛出异常。

  2. 根据方法的返回值类型和方法注解,分别从Retorfit对象的CallAdapter列表和Converter列表中分别获取对应的CallAdapter和Converter。

  3. 将传递过来的参数封装到ParameterHandler中,供后面网络请求使用。

2.1.2 使用OkHttpCall进行网络请求

loadServiceMethod方法之后,在invoke回调里使用new OkHttpCall<>(serviceMethod, args)创建了网络请求类OkHttpCall

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
private final ServiceMethod<T, ?> serviceMethod;
private final @Nullable Object[] args;

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

创建OkHttpCall时把刚才创建的ServiceMethod对象传了进去,就简单的存了一下,暂时并没做任何操作,我们继续往下看。

2.1.3 CallAdapter的使用

invoke最后一行

return serviceMethod.callAdapter.adapt(okHttpCall);

最后是调用了callAdapter的adapt方法,上面讲到Retrofit使用什么CallAdapter是根据我们在接口中定义的方法返回值,在例子中我们使用的是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;
  }

  if (scheduler != null) {
    observable = observable.subscribeOn(scheduler);
  }

  if (isFlowable) {
    return observable.toFlowable(BackpressureStrategy.LATEST);
  }
  if (isSingle) {
    return observable.singleOrError();
  }
  if (isMaybe) {
    return observable.singleElement();
  }
  if (isCompletable) {
    return observable.ignoreElements();
  }
  return RxJavaPlugins.onAssembly(observable);
}

首先在adapt方法中会先判断我们使用的是同步请求还是异步请求,这里我们分析同步请求里面做了什么操作(区别就是简单的异步还是同步请求而已)

final class CallExecuteObservable<T> extends Observable<Response<T>> {
  private final Call<T> originalCall;

  CallExecuteObservable(Call<T> originalCall) {
    this.originalCall = originalCall;
  }

  @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);
    if (disposable.isDisposed()) {
      return;
    }

    boolean terminated = false;
    try {
      Response<T> response = call.execute();
      if (!disposable.isDisposed()) {
        observer.onNext(response);
      }
      if (!disposable.isDisposed()) {
        terminated = true;
        observer.onComplete();
      }
    } catch (Throwable t) {
      Exceptions.throwIfFatal(t);
      if (terminated) {
        RxJavaPlugins.onError(t);
      } else if (!disposable.isDisposed()) {
        try {
          observer.onError(t);
        } catch (Throwable inner) {
          Exceptions.throwIfFatal(inner);
          RxJavaPlugins.onError(new CompositeException(t, inner));
        }
      }
    }
  }

  private static final class CallDisposable implements Disposable {
    private final Call<?> call;
    private volatile boolean disposed;

    CallDisposable(Call<?> call) {
      this.call = call;
    }

    @Override public void dispose() {
      disposed = true;
      call.cancel();
    }

    @Override public boolean isDisposed() {
      return disposed;
    }
  }
}

subscribeActual方法中调用了OkHttpCall的execute方法进行网络请求,请求响应回来后,通过RxJava的操作符对返回的数据进行转换,并切换线程。至此,Retrofit进行一次网络请求的主干思路就分析完了,是不是觉得很简单呢。下面我们看一下流程图

2.2 网络请求流程图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__Yvan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值