Retrofit源碼解析


序言

做Android開發(fā)的小伙伴都知道盯滚,現(xiàn)在最流行的網(wǎng)絡框架就是RxJava+Retrofi+OkHttp。今天我們就一起來學習一下Retrofit內部如何實現(xiàn)捂襟。

文章將會從下面幾個點展開介紹:

一、 如何使用Retrofit

二、 Retrofit源碼解析

1. 構建Retrofit對象
2. 創(chuàng)建Service實例
3. 執(zhí)行一次請求的具體流程

三而姐、總結

如何使用Retrofit

首先,介紹如何在我們的項目中使用Retrofit罚勾。
本文基于Retrofit2.0毅人,并且結合RxJava的使用進行分析,但不涉及RxJava原理分析尖殃。

  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 DeviceService {
    /**
     * 上傳用戶設備信息
     *
     * @param deviceInfo 設備信息
     */
    @POST(URLConstants.UPLOAD_DEVICE_INFO)
    @FormUrlEncoded
    Observable<BaseResponse<Object>> uploadDeviceInfo(@FieldMap Map<String, String> deviceInfo);
}
  1. 定義Retrofit
public enum DeviceRetrofit {
    SINGLETON;

    private static final String TAG = "DeviceRetrofit";
    private DeviceService mService;

    DeviceRetrofit() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(Config.HTTP_TIMEOUT, TimeUnit.MILLISECONDS)
                .retryOnConnectionFailure(true)
                .addInterceptor(new DeviceInterceptor())
                .addInterceptor(OkHttpUtils.getHttpInterceptor(TAG))
                .build();

        Retrofit retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl(Config.DEVICE_HOST)
                .addConverterFactory(JacksonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
        mService = retrofit.create(DeviceService.class);
    }

    public DeviceService getService() {
        return mService;
    }
}

DeviceRetrofit是一個單例類丈莺,通過枚舉實現(xiàn)單例模式,在構造方法中構建Retrofit對象送丰,用Retrofit初始化service對象缔俄,并且對外提供了service對象。

  1. 調用service方法發(fā)送請求
/**
 * 數(shù)據(jù)層DeviceModel
 */
public class DeviceModel extends BaseModel {
    /**
     * 上傳用戶設備信息
     */
    public Observable uploadDeviceInfo(UserDevBody userDevBody) {
        return DeviceRetrofit.SINGLETON.getService().uploadDeviceInfo(DeviceInfoHelper.transform(userDevBody))
                .compose(RxUtils.defaultResponse())
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io());
    }
}

到這里就已經(jīng)返回了一個經(jīng)過基礎轉換的Observable器躏,之后我們只需要對這個Observable進行處理俐载,得到我們想要的數(shù)據(jù)即可。

Retrofit源碼解析

可以說整個使用過程并不復雜登失,在我們用這么少的代碼就能夠發(fā)送一個網(wǎng)絡請求的背后遏佣,是Retrofit幫我們做了大量的工作,包括解析參數(shù)揽浙,組裝請求状婶,對數(shù)據(jù)進行轉換和適配...
下面我們通過源碼來分析Retrofit:

1. 構建Retrofit對象

我們先看一下構建Retrofit的代碼:

OkHttpClient okHttpClient = new OkHttpClient.Builder()
         .connectTimeout(Config.HTTP_TIMEOUT, TimeUnit.MILLISECONDS)
         .retryOnConnectionFailure(true)
         .addInterceptor(new DeviceInterceptor())
         .addInterceptor(OkHttpUtils.getHttpInterceptor(TAG))
         .build();
    
Retrofit retrofit = new Retrofit.Builder()
        .client(okHttpClient)
        .baseUrl(Config.DEVICE_HOST)
        .addConverterFactory(JacksonConverterFactory.create(mapper))
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

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包含一些重要的成員:

  • serviceMethodCache:是一個LinkedHashMap<Method, ServiceMethod>馅巷,聲明時直接初始化膛虫,用來緩存ServiceMethod,避免重復創(chuàng)建钓猬,可以提高性能
  • callFactory:請求工廠稍刀,主要要來創(chuàng)建請求(Call)
  • baseUrl:服務器域名,即服務器host
  • converterFactories:數(shù)據(jù)解析工廠敞曹,可以創(chuàng)建Converter账月,主要用來解析Response综膀,可以有多個,但只有一個會進行真正的解析操作
  • adapterFactories:數(shù)據(jù)適配工廠捶障,可以創(chuàng)建適配器僧须,主要作用是把Response中的數(shù)據(jù)轉換為某種數(shù)據(jù)源類型,比如我們示例中把Response轉換為rxjava.Observable
  • callbackExecutor:請求線程池
  • validateEagerly:是否設置為饑餓模式项炼,如果設置為饑餓模式担平,會提前初始化ServiceMethod,后面分析中會做介紹

分析完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的靜態(tài)內部類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大部分成員:

  • baseUrl:我們通過builder對象手動設置您市,例子中的是Config.DEVICE_HOST觉痛,只需要知道,這是一個host就可以
  • callFactory:我們通過builder設置的OkHttpClient對象
  • callExecutor:platform.defaultCallbackExecutor茵休,Android平臺是MainThreadExecutor類型薪棒,它是主線程線程池,所有的請求都是在主線程發(fā)送一個消息榕莺,在異步線程中執(zhí)行請求赃阀,最后在主線程中處理回調
  • adapterFactories:添加一個ExecutorCallAdapterFactory澎媒,而我們又通過bulder設置了一個RxJavaCallAdapterFactory镇眷,所以adapterFactories中有兩個元素鼓鲁,最后會使用到RxJavaCallAdapterFactory
  • converterFactories:通過builder設置,是JacksonConverterFactory類型
  • validateEagerly:默認為false

可以看到唠雕,在Retrofit.Builder.build方法中贸营,初始化了Retrofit所有的成員。

至此及塘,構建Retrofit對象的過程介紹完畢∪窦總結一下笙僚,就是創(chuàng)建了一個Retrofit對象,并且初始化了它的所有成員變量灵再。

2. 創(chuàng)建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就是為一個方法創(chuàng)建一個ServiceMethod對象,可見validateEagerly的作用就是提前初始化Service方法對應的ServiceMethod雌团。
至于ServiceMethod是什么燃领,我們后面分析。

動態(tài)代理

使用動態(tài)代理模式構建Service實例锦援,了解動態(tài)代理的同學知道猛蔽,動態(tài)代理可以自動幫我們生成代理類,我們調用代理類的方法灵寺,最后都會調用到InvocationHandler的invoke方法曼库,它的好處在于可以對所有方法做統(tǒng)一處理。
而Retrofit正是需要對Service的方法做統(tǒng)一處理:

  • 判斷方法是否屬于Object略板,如果是的毁枯,直接調用方法
  • 判斷方法是否為platform的默認方法,Android平臺都返回false
  • 方法屬于Service蚯根,則會執(zhí)行以下三句代碼(因為是Android平臺后众,所以肯定會走到這里):
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);

到這里,創(chuàng)建Service實例完畢颅拦〉儆總結一下,Retrofit通過動態(tài)代理的方式初始化一個實現(xiàn)了Service的代理類距帅。

3. 執(zhí)行一次請求的具體流程

Retrofit和Service初始化之后右锨,我們嘗試進行一次請求,即調用一次Service的方法碌秸,它的流程是什么樣的呢?

這就要回到上面介紹的動態(tài)代理绍移,每次調用service方法最后都會執(zhí)行InvocationHandler.invoke方法,這個方法對所有的請求做統(tǒng)一處理讥电,即上面提到的三句代碼蹂窖,下面逐句分析:

第一句:構建一個ServiceMethod對象
ServiceMethod serviceMethod = loadServiceMethod(method);

在饑餓模式中也提到了loadServiceMethod方法的,這個方法會接收method作為參數(shù)恩敌,返回一個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瞬测,如果沒有,創(chuàng)建一個ServiceMethod對象,并且把<method, MethodService>保存到serviceMethodCache中月趟,下次調該方法就可以直接從serviceMethodCache中獲取ServiceMethod灯蝴,而不用重復創(chuàng)建,提高性能孝宗。
ServiceMethod也采用Builder模式來創(chuàng)建對象穷躁,我們先看一下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請求有關的一些參數(shù),在Builder.build方法中會初始化這些參數(shù):

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的成員變量及構造過程中初始化情況:

  • callFactory:跟Retrofit.callFactory一樣沙峻,即OkHttpClient
  • callAdapter:根據(jù)方法的返回類型睦授,從Retrofit的兩個callFactory中匹配得到RxJavaCallAdapterFactory,具體匹配過程同學們可以自行跟蹤代碼摔寨。通過RxJavaCallAdapterFactory創(chuàng)建該方法對應的RxJavaCallAdapterFactory.SimpleCallAdapter
  • baseUrl:同Retrofit的baseUrl一致
  • responseConverter:通過Retrofit的converterFactory創(chuàng)建的JacksonResponseBodyConverter對象
  • httpMethod:從方法注解中解析得到去枷,即GETPOST等Http請求類型
  • relativeUrl:請求地址是复,一般是從請求類型注解中解析得到删顶,如@GET("order/query/101")對應的relativeUrl是order/query/101
  • header:請求頭信息,從方法注解@Headers中解析得到
  • contentType:請求的數(shù)據(jù)類型淑廊,從@Headers中解析得到
  • hasBody:請求是否有內容部分(body)逗余,DELETE/GET/HEAD/OPTIONS類型的請求沒有,POST/PATCH/PUT類型請求有
  • isFormEncoded:從方法上是否有@FormUrlEncoded判斷季惩,不能與@Multipart同時存在录粱,前提條件是hasBody=true
  • isMultipart:從方法上是否有@Multipart判斷,不能與@FormUrlEncoded同時存在画拾,前提條件是hasBody=true
  • parameterHandlers:數(shù)組類型啥繁,從方法的參數(shù)注解解析得到,數(shù)量與方法參數(shù)數(shù)量一直青抛,作用是參數(shù)信息設置到Http請求構造器RequestBuilder中

可以看到旗闽,loadServiceMethod方法就是根據(jù)method構建一個ServiceMethod對象。在構建的過程中蜜另,解析方法上的注解和參數(shù)注解适室,初始化ServiceMethod的所有成員變量。
具體的解析過程不詳細介紹举瑰,代碼比較多捣辆,對著可以自己參照源碼學習。

第二句:創(chuàng)建OkHttpCall
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

OkHttpCall是Call的實現(xiàn)類此迅,定義如下:

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和參數(shù)數(shù)組促煮,并且還有還有一個成員rawCall(okhttp3.Call類型),它的作用是執(zhí)行請求并且管理請求的狀態(tài)和處理請求回調整袁。

第三句:執(zhí)行請求
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的實現(xiàn):

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實現(xiàn)了rxjava中的Observable.OnSubscribe接口,當Observable對象調用subscribe方法的時候芋忿,就會執(zhí)行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方法創(chuàng)建call對象(okhttp3.Call)殉了,然后調用call.execute()方法开仰,并且用convert把響應結果轉換為Response對象。
這段代碼我們關注兩個點:a. 初始化call對象 b. 調用call.execute方法執(zhí)行請求薪铜。下面一次介紹:
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 */);
}

這里創(chuàng)建了一個RealCall對象谓娃,它是OkHttp中Call的實現(xiàn)類,是真正的請求類蜒滩。

b. 調用call.execute方法執(zhí)行請求
真正的請求類是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的請求機制,這里不做解釋俯艰,后面會單獨出一篇OkHttp的文章捡遍。
總之執(zhí)行了請求之后,會生成一個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源碼的過程中良拼,往往會陷入細節(jié)中無法自拔,導致不能對Retrofit整體把握充边。下面庸推,是我自己梳理的一張Retrofit架構圖常侦,包括一次請求執(zhí)行的流程:


Retrofit架構流程圖.png

這張圖基本概括了上面描述的所有內容,如果各位有什么不懂的歡迎提問贬媒。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末聋亡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子际乘,更是在濱河造成了極大的恐慌坡倔,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脖含,死亡現(xiàn)場離奇詭異罪塔,居然都是意外死亡,警方通過查閱死者的電腦和手機养葵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門征堪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來关拒,“玉大人佃蚜,你說我怎么就攤上這事着绊。” “怎么了畔柔?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵靶擦,是天一觀的道長腮考。 經(jīng)常有香客問我玄捕,道長,這世上最難降的妖魔是什么枚粘? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮福也,結果婚禮上,老公的妹妹穿的比我還像新娘暴凑。我一直安慰自己,他們只是感情好现喳,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嗦篱,像睡著了一般冰单。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灸促,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天球凰,我揣著相機與錄音腿宰,去河邊找鬼缘厢。 笑死吃度,一個胖子當著我的面吹牛贴硫,可吹牛的內容都是我干的。 我是一名探鬼主播英遭,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼汁尺!你這毒婦竟也來了?” 一聲冷哼從身側響起痴突,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤狼荞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后相味,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡拓巧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年一死,在試婚紗的時候發(fā)現(xiàn)自己被綠了玲销。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡贤斜,死狀恐怖策吠,靈堂內的尸體忽然破棺而出瘩绒,到底是詐尸還是另有隱情,我是刑警寧澤锁荔,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站阳堕,受9級特大地震影響,放射性物質發(fā)生泄漏前普。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一拭卿、第九天 我趴在偏房一處隱蔽的房頂上張望贱纠。 院中可真熱鬧峻厚,春花似錦谆焊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽誓禁。三九已至肾档,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間怒见,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工闺阱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留舵变,地道東北人瘦穆。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓赊豌,卻偏偏與公主長得像扛或,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子熙兔,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內容