Android开发经验谈Android开发面试题

Retrofit源码解析

2019-10-05  本文已影响0人  4e70992f13e7

序言

做Android开发的小伙伴都知道,现在最流行的网络框架就是RxJava+Retrofi+OkHttp。今天我们就一起来学习一下Retrofit内部如何实现。

一.如何使用Retrofit

  1. 在工程Module的build.gradle中添加Retrofit依赖库:
api "com.squareup.retrofit2:retrofit:2.0.0"
api "com.squareup.retrofit2:adapter-rxjava:2.0.0"
api "com.squareup.retrofit2:converter-jackson:2.0.0"
  1. 定义一个提供服务的接口Service:
public interface APIService {
    @GET("hello/world")
    Observable<Response<String>> getNews(@Query("num") String num, @Query("page")String page);
}
  1. 使用
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://apis.baidu.com/txapi/")
                .addConverterFactory(JacksonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();

        APIService service = retrofit.create(APIService.class);
        service.getNews("10","1")
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .subscribe(new Action1<Response<String>>() {
                    @Override
                    public void call(Response<String> response) {
                        
                    }
                });

到这里就已经返回了一个经过基础转换的Observable,之后我们只需要对这个Observable进行处理,得到我们想要的数据即可。

二.Retrofit源码解析

可以说整个使用过程并不复杂,在我们用这么少的代码就能够发送一个网络请求的背后,是Retrofit帮我们做了大量的工作,包括解析参数,组装请求,对数据进行转换和适配...
下面我们通过源码来分析Retrofit:

1. 构建Retrofit对象

Retrofit是通过Builder模式来构建对象,我们先看一下Retrofit的定义:

public final class Retrofit {
    private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
    
    private final okhttp3.Call.Factory callFactory;
    private final HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories;
    private final List<CallAdapter.Factory> adapterFactories;
    private final Executor callbackExecutor;
    private final boolean validateEagerly;
    
    Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
        List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
        Executor callbackExecutor, boolean validateEagerly) {
        this.callFactory = callFactory;
        this.baseUrl = baseUrl;
        this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
        this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
        this.callbackExecutor = callbackExecutor;
        this.validateEagerly = validateEagerly;
    }

    //省略其他代码
}

Retrofit包含一些重要的成员:

分析完Retrofit中的成员变量之后,我们来看一下Builder如何初始化这些成员变量,先看一下Builder的构造方法:

public Builder() {
    this(Platform.get());
}

需要传一个Platform对象:

class Platform {
    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) {
      }
      try {
        Class.forName("org.robovm.apple.foundation.NSObject");
        return new IOS();
      } catch (ClassNotFoundException ignored) {
      }
      return new Platform();
    }
}

Platform.get方法返回PLATFORM成员,而这个成员通过findPlatform方法初始化,我们使用的是Android平台,所以直接返回一个Android对象,接下来看一下Platform的静态内部类Android的定义:

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

Platform的作用是帮助初始化Retrofit。而不同的平台会使用不同的对象去初始化Retrofit,我们只关心Android平台。
接下来看一下Builder的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);
}

build方法会初始化Retrofit大部分成员:

可以看到,在Retrofit.Builder.build方法中,初始化了Retrofit所有的成员。

至此,构建Retrofit对象的过程介绍完毕。总结一下,就是创建了一个Retrofit对象,并且初始化了它的所有成员变量。

2. 创建Service实例

Retrofit对象初始化之后,就会初始化Service对象,代码如下:

mService = retrofit.create(DeviceService.class);

Retrofit调用create方法初始化Service对象:

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

这段代码中,我们着重看两个地方:

饥饿模式

如果validateEagerly为true,就会调用eagerlyValidateMethod方法:

private void eagerlyValidateMethods(Class<?> service) {
  Platform platform = Platform.get();
  for (Method method : service.getDeclaredMethods()) {
    if (!platform.isDefaultMethod(method)) {
      loadServiceMethod(method);
    }
  }
}

这个方法通过反射,获取Service中定义的所有方法,并且遍历,对每个方法做loadServiceMethod处理,而loadServiceMethod就是为一个方法创建一个ServiceMethod对象,可见validateEagerly的作用就是提前初始化Service方法对应的ServiceMethod。
至于ServiceMethod是什么,我们后面分析。

动态代理

使用动态代理模式构建Service实例,了解动态代理的同学知道,动态代理可以自动帮我们生成代理类,我们调用代理类的方法,最后都会调用到InvocationHandler的invoke方法,它的好处在于可以对所有方法做统一处理。
而Retrofit正是需要对Service的方法做统一处理:

ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);

到这里,创建Service实例完毕。总结一下,Retrofit通过动态代理的方式初始化一个实现了Service的代理类。

3.ServiceMethod对象

Retrofit和Service初始化之后,我们尝试进行一次请求,即调用一次Service的方法,它的流程是什么样的呢?

这就要回到上面介绍的动态代理,每次调用service方法最后都会执行InvocationHandler.invoke方法,这个方法对所有的请求做统一处理,即上面提到的三句代码,下面逐句分析:

第一句:构建一个ServiceMethod对象
ServiceMethod serviceMethod = loadServiceMethod(method);

在饥饿模式中也提到了loadServiceMethod方法的,这个方法会接收method作为参数,返回一个ServiceMethod对象:

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

先从serviceMethodCache找是否存在该方法对应的ServiceMethod,如果没有,创建一个ServiceMethod对象,并且把<method, MethodService>保存到serviceMethodCache中,下次调该方法就可以直接从serviceMethodCache中获取ServiceMethod,而不用重复创建,提高性能。
ServiceMethod也采用Builder模式来创建对象,我们先看一下ServiceMethod的定义:

/** Adapts an invocation of an interface method into an HTTP call. */
final class ServiceMethod<T> {
  // Upper and lower characters, digits, underscores, and hyphens, starting with a character.
  static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
  static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
  static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);

  final okhttp3.Call.Factory callFactory;
  final CallAdapter<?> callAdapter;

  private final HttpUrl baseUrl;
  private final Converter<ResponseBody, T> responseConverter;
  private final String httpMethod;
  private final String relativeUrl;
  private final Headers headers;
  private final MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;

  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的类注释介绍了它的作用,就是把一次接口的方法调用转换成一个Http请求。它也包含了很多成员变量,都是与Http请求有关的一些参数,在Builder.build方法中会初始化这些参数:

public Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  this.methodAnnotations = method.getAnnotations();
  this.parameterTypes = method.getGenericParameterTypes();
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}
 
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);
}

可以看出ServiceMethod的build()方法里面主要做的事情是callAdapter, responseConverter实例的获取,以及解析方法注解,我们来看下callAdapter的实例是怎么获取的

private CallAdapter<T, R> createCallAdapter() {
  Type returnType = method.getGenericReturnType();
  ...
  Annotation[] annotations = method.getAnnotations();
  try {
    //noinspection unchecked
    return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
  } catch (RuntimeException e) { // Wide exception range because factories are user code.
    throw methodError(e, "Unable to create call adapter for %s", returnType);
  }
}

可以看出还是要调用retrofit的callAdapter方法

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
  return nextCallAdapter(null, returnType, annotations);
}

  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    ...
    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
   ...

代码片段省略了部分,最后还是会走到nextCallAdapter方法去获取其实例,callAdapter实例会从adapterFactories获取,由于获取的是一个工厂类还是要调用一个get方法从工厂获取其callAdapter对象。adapterFactories就是我们获取Retrofit实例时候传入的,可以自定义,也可以用别人提供的,先设置的满足条件,先会被使用。

responseConverter也是一样的方法去获取其实例。

下面列举一下ServiceMethod的成员变量及构造过程中初始化情况:

第二句:创建OkHttpCall
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

OkHttpCall是Call的实现类,定义如下:

final class OkHttpCall<T> implements Call<T> {
  private final ServiceMethod<T> serviceMethod;
  private final Object[] args;

  private volatile boolean canceled;

  // All guarded by this.
  private okhttp3.Call rawCall;
  private Throwable creationFailure; // Either a RuntimeException or IOException.
  private boolean executed;

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

  //省略其他代码
}

从定义中可知,OkHttpCall构造方法接收ServiceMethod和参数数组,并且还有还有一个成员rawCall(okhttp3.Call类型),它的作用是执行请求并且管理请求的状态和处理请求回调。

第三句:执行请求
return serviceMethod.callAdapter.adapt(okHttpCall);

调用了callAdapter.adapt方法,而serviceMethod.callAdapter是RxJavaCallAdapterFactory.SimpleCallAdapter对象,所以我们直接看SimpleCallAdapter的adapt方法:

static final class SimpleCallAdapter implements CallAdapter<Observable<?>> {
  private final Type responseType;
  private final Scheduler scheduler;

  SimpleCallAdapter(Type responseType, Scheduler scheduler) {
    this.responseType = responseType;
    this.scheduler = scheduler;
  }

  @Override public Type responseType() {
    return responseType;
  }

  @Override public <R> Observable<R> adapt(Call<R> call) {
    Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) //
        .flatMap(new Func1<Response<R>, Observable<R>>() {
          @Override public Observable<R> call(Response<R> response) {
            if (response.isSuccessful()) {
              return Observable.just(response.body());
            }
            return Observable.error(new HttpException(response));
          }
        });
    if (scheduler != null) {
      return observable.subscribeOn(scheduler);
    }
    return observable;
  }
}

用CallOnSubscribe构建了一个Observable对象,看一下CallOnSubscribe的实现:

static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
  private final Call<T> originalCall;

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

  @Override public void call(final Subscriber<? super Response<T>> subscriber) {
    // Since Call is a one-shot type, clone it for each new subscriber.
    final Call<T> call = originalCall.clone();

    // Attempt to cancel the call if it is still in-flight on unsubscription.
    subscriber.add(Subscriptions.create(new Action0() {
      @Override public void call() {
        call.cancel();
      }
    }));

    try {
      Response<T> response = call.execute();
      if (!subscriber.isUnsubscribed()) {
        subscriber.onNext(response);
      }
    } catch (Throwable t) {
      Exceptions.throwIfFatal(t);
      if (!subscriber.isUnsubscribed()) {
        subscriber.onError(t);
      }
      return;
    }

    if (!subscriber.isUnsubscribed()) {
      subscriber.onCompleted();
    }
  }
}

CallOnSubscribe实现了rxjava中的Observable.OnSubscribe接口,当Observable对象调用subscribe方法的时候,就会执行OnSubscribe的call方法(可参照RxJava源码)。
call方法中着重关注call.execute()这句代码,这里的call是上面提到的的OkHttpCall对象,所以看OkHttpCall的execute方法:

@Override public Response<T> execute() throws IOException {
  okhttp3.Call call;

  synchronized (this) {
    if (executed) throw new IllegalStateException("Already executed.");
    executed = true;

    if (creationFailure != null) {
      if (creationFailure instanceof IOException) {
        throw (IOException) creationFailure;
      } else {
        throw (RuntimeException) creationFailure;
      }
    }

    call = rawCall;
    if (call == null) {
      try {
        call = rawCall = createRawCall();
      } catch (IOException | RuntimeException e) {
        creationFailure = e;
        throw e;
      }
    }
  }

  if (canceled) {
    call.cancel();
  }

  return parseResponse(call.execute());
}

主要逻辑:检查call是否为空,如果为空,则调用createRawCall方法创建call对象(okhttp3.Call),然后调用call.execute()方法,并且用convert把响应结果转换为Response对象。
这段代码我们关注两个点:a. 初始化call对象 b. 调用call.execute方法执行请求。下面一次介绍:
a. 初始化call对象

private okhttp3.Call createRawCall() throws IOException {
  Request request = serviceMethod.toRequest(args);
  okhttp3.Call call = serviceMethod.callFactory.newCall(request);
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

先把ServiceMethod转化为Request对象,然后用Request构建一个okhttp3.Call对象,serviceMethod.callFactory是OkHttpClient对象,跟踪到OkHttpClient.newCall方法:

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

这里创建了一个RealCall对象,它是OkHttp中Call的实现类,是真正的请求类。

b. 调用call.execute方法执行请求
真正的请求类是RawCall,所以我们直接看RawCall的execute方法:

@Override public Response execute() throws IOException {
    synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  eventListener.callStart(this);
  try {
    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain();
    if (result == null) throw new IOException("Canceled");
    return result;
  } catch (IOException e) {
    eventListener.callFailed(this, e);
    throw e;
  } finally {
    client.dispatcher().finished(this);
  }
}

这段代码就涉及到OkHttp的请求机制,这里不做解释,如果有不理解的同学,自行补习。
总之执行了请求之后,会生成一个okhttp3.Response对象,然后通过OkHttpCall.parseResponse方法把okhttp3.Response转换为retrofit2.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();
  if (code < 200 || code >= 300) {
    try {
      // Buffer the entire body to avoid future I/O.
      ResponseBody bufferedBody = Utils.buffer(rawBody);
      return Response.error(bufferedBody, rawResponse);
    } finally {
      rawBody.close();
    }
  }

  if (code == 204 || code == 205) {
    return Response.success(null, rawResponse);
  }

  ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
  try {
    T body = serviceMethod.toResponse(catchingBody);
    return Response.success(body, rawResponse);
  } catch (RuntimeException e) {
    // If the underlying source threw an exception, propagate that rather than indicating it was
    // a runtime exception.
    catchingBody.throwIfCaught();
    throw e;
  }
}

这里返回的Response交给RxJava处理,最后返回给客户端。到此,一个请求的整个流程就介绍完毕了。

Retrofit中使用了大量的设计模式,下面是从网上找的一张图


设计模式
上一篇 下一篇

猜你喜欢

热点阅读